From 73cf372fd21e2a42c93d70c02f6e2ae187383f14 Mon Sep 17 00:00:00 2001 From: Michihiro NAKAJIMA Date: Fri, 16 Oct 2009 12:42:36 -0400 Subject: [PATCH] Add support for multi extent. e.g. -- Reuslt of previous bsdtar. %bsdtar tvf test_read_format_iso_multi_extent.iso dr-xr-xr-x 2 1 2 2048 1 2 1970 . -r--r--r-- 1 1 2 129024 1 2 1970 file -r--r--r-- 1 1 2 129024 1 2 1970 file -r--r--r-- 1 1 2 4232 1 2 1970 file -- After patch. %bsdtar tvf test_read_format_iso_multi_extent.iso dr-xr-xr-x 2 1 2 2048 1 2 1970 . -r--r--r-- 1 1 2 262280 1 2 1970 file SVN-Revision: 1537 --- Makefile.am | 2 + .../archive_read_support_format_iso9660.c | 103 +++++++++++++++++- libarchive/test/CMakeLists.txt | 1 + .../test/test_read_format_iso_multi_extent.c | 100 +++++++++++++++++ ...st_read_format_iso_multi_extent.iso.bz2.uu | 24 ++++ 5 files changed, 224 insertions(+), 6 deletions(-) create mode 100644 libarchive/test/test_read_format_iso_multi_extent.c create mode 100644 libarchive/test/test_read_format_iso_multi_extent.iso.bz2.uu diff --git a/Makefile.am b/Makefile.am index b14cf4585..e1e18f63f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -257,6 +257,7 @@ libarchive_test_SOURCES= \ libarchive/test/test_read_format_gtar_lzma.c \ libarchive/test/test_read_format_gtar_sparse.c \ libarchive/test/test_read_format_iso_gz.c \ + libarchive/test/test_read_format_iso_multi_extent.c \ libarchive/test/test_read_format_isojoliet_bz2.c \ libarchive/test/test_read_format_isojoliet_long.c \ libarchive/test/test_read_format_isojoliet_rr.c \ @@ -342,6 +343,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_gtar_sparse_1_17_posix10.tar.uu \ libarchive/test/test_read_format_gtar_sparse_1_17_posix10_modified.tar.uu \ libarchive/test/test_read_format_iso_gz.iso.gz.uu \ + libarchive/test/test_read_format_iso_multi_extent.iso.gz.uu \ libarchive/test/test_read_format_isojoliet_bz2.iso.bz2.uu \ libarchive/test/test_read_format_isojoliet_long.iso.bz2.uu \ libarchive/test/test_read_format_isojoliet_rr.iso.bz2.uu \ diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c index 0a7297380..f0be5c5f3 100644 --- a/libarchive/archive_read_support_format_iso9660.c +++ b/libarchive/archive_read_support_format_iso9660.c @@ -247,6 +247,12 @@ struct zisofs { }; #endif +struct content { + uint64_t offset;/* Offset on disk. */ + uint64_t size; /* File size in bytes. */ + struct content *next; +}; + /* In-memory storage for a directory record. */ struct file_info { struct file_info *parent; @@ -277,6 +283,12 @@ struct file_info { int pz; int pz_log2_bs; /* Log2 of block size */ uint64_t pz_uncompressed_size; + /* Set 1 if this file is multi extent. */ + int multi_extent; + struct { + struct content *first; + struct content **last; + } contents; }; struct heap_queue { @@ -333,6 +345,7 @@ struct iso9660 { off_t entry_sparse_offset; int64_t entry_bytes_remaining; struct zisofs entry_zisofs; + struct content *entry_content; }; static int archive_read_format_iso9660_bid(struct archive_read *); @@ -734,6 +747,7 @@ read_children(struct archive_read *a, struct file_info *parent) { struct iso9660 *iso9660; const unsigned char *b, *p; + struct file_info *multi; size_t step; iso9660 = (struct iso9660 *)(a->format->data); @@ -772,6 +786,7 @@ read_children(struct archive_read *a, struct file_info *parent) } __archive_read_consume(a, step); iso9660->current_position += step; + multi = NULL; while (step) { p = b; b += iso9660->logical_block_size; @@ -798,8 +813,41 @@ read_children(struct archive_read *a, struct file_info *parent) if (child->cl_offset) heap_add_entry(iso9660, &(iso9660->cl_files), child); - else - add_entry(iso9660, child); + else { + if (child->multi_extent || multi != NULL) { + struct content *con; + + if (multi == NULL) { + multi = child; + multi->contents.first = NULL; + multi->contents.last = + &(multi->contents.first); + } + con = malloc(sizeof(struct content)); + if (con == NULL) { + release_file(iso9660, child); + archive_set_error( + &a->archive, ENOMEM, + "No memory for " + "multi extent"); + return (ARCHIVE_FATAL); + } + con->offset = child->offset; + con->size = child->size; + con->next = NULL; + *multi->contents.last = con; + multi->contents.last = &(con->next); + if (multi == child) + add_entry(iso9660, child); + else { + multi->size += child->size; + if (!child->multi_extent) + multi = NULL; + release_file(iso9660, child); + } + } else + add_entry(iso9660, child); + } } } @@ -1096,6 +1144,11 @@ archive_read_format_iso9660_read_header(struct archive_read *a, iso9660->previous_number = file->number; archive_strcpy(&iso9660->previous_pathname, iso9660->pathname.s); + /* Reset entry_bytes_remaining if the file is multi extent. */ + iso9660->entry_content = file->contents.first; + if (iso9660->entry_content != NULL) + iso9660->entry_bytes_remaining = iso9660->entry_content->size; + if (archive_entry_filetype(entry) == AE_IFDIR) { /* Overwrite nlinks by proper link number which is * calculated from number of sub directories. */ @@ -1365,10 +1418,37 @@ archive_read_format_iso9660_read_data(struct archive_read *a, iso9660 = (struct iso9660 *)(a->format->data); if (iso9660->entry_bytes_remaining <= 0) { - *buff = NULL; - *size = 0; - *offset = iso9660->entry_sparse_offset; - return (ARCHIVE_EOF); + if (iso9660->entry_content != NULL) + iso9660->entry_content = iso9660->entry_content->next; + if (iso9660->entry_content == NULL) { + *buff = NULL; + *size = 0; + *offset = iso9660->entry_sparse_offset; + return (ARCHIVE_EOF); + } + /* Seek forward to the start of the entry. */ + if (iso9660->current_position < iso9660->entry_content->offset) { + int64_t step; + + step = iso9660->entry_content->offset - + iso9660->current_position; + step = __archive_read_skip(a, step); + if (step < 0) + return ((int)step); + iso9660->current_position = + iso9660->entry_content->offset; + } + if (iso9660->entry_content->offset < iso9660->current_position) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Ignoring out-of-order file (%s) %jd < %jd", + iso9660->pathname.s, + iso9660->entry_content->offset, + iso9660->current_position); + iso9660->entry_bytes_remaining = 0; + iso9660->entry_sparse_offset = 0; + return (ARCHIVE_WARN); + } + iso9660->entry_bytes_remaining = iso9660->entry_content->size; } if (iso9660->entry_zisofs.pz) return (zisofs_read_data(a, buff, size, offset)); @@ -1556,6 +1636,10 @@ parse_file_info(struct archive_read *a, struct file_info *parent, file->mode = AE_IFDIR | 0700; else file->mode = AE_IFREG | 0400; + if (flags & 0x80) + file->multi_extent = 1; + else + file->multi_extent = 0; /* * Use location for file number. * File number is treated as inode number to find out harlink @@ -2154,6 +2238,7 @@ static void release_file(struct iso9660 *iso9660, struct file_info *file) { struct file_info *parent; + struct content *con, *connext; if (file == NULL) return; @@ -2162,6 +2247,12 @@ release_file(struct iso9660 *iso9660, struct file_info *file) parent = file->parent; archive_string_free(&file->name); archive_string_free(&file->symlink); + con = file->contents.first; + while (con != NULL) { + connext = con->next; + free(con); + con = connext; + } free(file); if (parent != NULL) { parent->refcount--; diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index 7619150bc..4b585f6fd 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -56,6 +56,7 @@ IF(ENABLE_TEST) test_read_format_gtar_lzma.c test_read_format_gtar_sparse.c test_read_format_iso_gz.c + test_read_format_iso_multi_extent.c test_read_format_isojoliet_bz2.c test_read_format_isojoliet_long.c test_read_format_isojoliet_rr.c diff --git a/libarchive/test/test_read_format_iso_multi_extent.c b/libarchive/test/test_read_format_iso_multi_extent.c new file mode 100644 index 000000000..53e576ba4 --- /dev/null +++ b/libarchive/test/test_read_format_iso_multi_extent.c @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2009 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" + +DEFINE_TEST(test_read_format_iso_multi_extent) +{ + const char *refname = "test_read_format_iso_multi_extent.iso.bz2"; + struct archive_entry *ae; + struct archive *a; + const void *p; + size_t size; + off_t offset; + int i; + int r; + + extract_reference_file(refname); + assert((a = archive_read_new()) != NULL); + r = archive_read_support_compression_bzip2(a); + if (r == ARCHIVE_WARN) { + skipping("bzip2 reading not fully supported on this platform"); + assertEqualInt(0, archive_read_finish(a)); + return; + } + assertEqualInt(0, r); + assertEqualInt(0, archive_read_support_format_all(a)); + assertEqualInt(ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + /* Retrieve each of the 2 files on the ISO image and + * verify that each one is what we expect. */ + for (i = 0; i < 2; ++i) { + assertEqualInt(0, archive_read_next_header(a, &ae)); + + if (strcmp(".", archive_entry_pathname(ae)) == 0) { + /* '.' root directory. */ + assertEqualInt(AE_IFDIR, archive_entry_filetype(ae)); + assertEqualInt(2048, archive_entry_size(ae)); + assertEqualInt(86401, archive_entry_mtime(ae)); + assertEqualInt(0, archive_entry_mtime_nsec(ae)); + assertEqualInt(2, archive_entry_stat(ae)->st_nlink); + assertEqualInt(1, archive_entry_uid(ae)); + assertEqualIntA(a, ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 0); + } else if (strcmp("file", archive_entry_pathname(ae)) == 0) { + /* A regular file. */ + assertEqualString("file", archive_entry_pathname(ae)); + assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); + assertEqualInt(262280, archive_entry_size(ae)); + assertEqualInt(0, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt(0, offset); + assertEqualMem(p, "head--head--head", 16); + assertEqualInt(86401, archive_entry_mtime(ae)); + assertEqualInt(86401, archive_entry_atime(ae)); + assertEqualInt(1, archive_entry_stat(ae)->st_nlink); + assertEqualInt(1, archive_entry_uid(ae)); + assertEqualInt(2, archive_entry_gid(ae)); + } else { + failure("Saw a file that shouldn't have been there"); + assertEqualString(archive_entry_pathname(ae), ""); + } + } + + /* End of archive. */ + assertEqualInt(ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + /* Verify archive format. */ + assertEqualInt(archive_compression(a), ARCHIVE_COMPRESSION_BZIP2); + assertEqualInt(archive_format(a), ARCHIVE_FORMAT_ISO9660_ROCKRIDGE); + + /* Close the archive. */ + assertEqualInt(0, archive_read_close(a)); + assertEqualInt(0, archive_read_finish(a)); +} + + diff --git a/libarchive/test/test_read_format_iso_multi_extent.iso.bz2.uu b/libarchive/test/test_read_format_iso_multi_extent.iso.bz2.uu new file mode 100644 index 000000000..b414b5bcf --- /dev/null +++ b/libarchive/test/test_read_format_iso_multi_extent.iso.bz2.uu @@ -0,0 +1,24 @@ +begin 644 test_read_format_iso_multi_extent.iso.bz2 +M0EIH.3%!62936?,G"4,``1Y_[??U9_?6%_FZ/^_?X;]GG89@Z,`"``4!```" +M@$C0`V\$@Z6W'77#**>C48IZ:0>C(F@`&CU&AH#0#30``'J&@/4]0-!$:$;4 +MF(:`R``-``````:``!H#32"*9/TH/4::`````9&0``#0&@``'`T!H-&@9-`` +M:``Q-#30--`#1HT`#1H(DD$B;133/4T:GJ!DTV0R`RAAJ#3:`F`T#0"`("P7 +M`D/7M82QF:&0!.)GBD1`8:9M'Y,CE3`2M`J59X%MJMB-H22,$<2(!R(`:T_B +M;$07,$0$3FP4`%RP!4\=U+FS9YH*"JAIC["B&(!1`@BZ-2AJ*HBACC0KR!2* +M#5I)*&X^L^]+!K_+>PN+FJ]FSH"O[16Z".[5(HD@AUXJ=F:>K6.>XDU"M79, +M$ZR;+`WEI4[;W.3C%ME<(,H#TUFTMNWBSU47WEIK\T,K[72N@TH.)JU7\HPQ +MP%H^!\C2K3B6VTV+"$)!(!!(&&+(68C0;P[5&QV+@?N"Z^Q_?Z79Q+YT7/<0 +M+%)P12P]3<3+84W7&CAU\;C@I^^`;Y@FD.4N5L*0HB$C_54R*:Z0\VZF#8?J +M(-,,!3::,]+%W3VRD_DP7LCK=NU6JW&2G.(1G,HI(Y)ZBQ03(0!$(=,@=#2M +MPH7MZ]B+XOALU^&CG3J^K,UA0M$;*K*5-:IA8/BTW0HOG1HDH^S@6H/,DH8$ +M(#%"0B]*7F9-[W)UDWD^$3-PO!JT^?@&D:,`O&&P<=L.1>'K8(;8^G.&P-PP +M;7T/MW[]]PP,IE/]6*>HI!:V`2:1#%(10D2L(1LUSVJY-V?FBLQAQW_`;:9E +MS%@<2+@B2,Q7]7?]J<1=B$`::Z`X)CQ4&$(3<8`2Q0]^N<#B;6,#