]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Add support for multi extent.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Fri, 16 Oct 2009 16:42:36 +0000 (12:42 -0400)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Fri, 16 Oct 2009 16:42:36 +0000 (12:42 -0400)
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
libarchive/archive_read_support_format_iso9660.c
libarchive/test/CMakeLists.txt
libarchive/test/test_read_format_iso_multi_extent.c [new file with mode: 0644]
libarchive/test/test_read_format_iso_multi_extent.iso.bz2.uu [new file with mode: 0644]

index b14cf4585f7ad2804b559cc401b13c5de41f0857..e1e18f63fbcbf0123d6cb90fbe956ab37f9bc74f 100644 (file)
@@ -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        \
index 0a7297380abf56bf11a8eda7862d53b325fb42e7..f0be5c5f38441d6367fbf89b2c3d795997fd3c5c 100644 (file)
@@ -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--;
index 7619150bc9d38dd36cecc14724742b8e0d6ac52b..4b585f6fdd29d79e60ffe240c1f2f9f0743f7e81 100644 (file)
@@ -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 (file)
index 0000000..53e576b
--- /dev/null
@@ -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 (file)
index 0000000..b414b5b
--- /dev/null
@@ -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,#<R<8FO6!
+MHUJ7&.4ZQ!]Z9DH,4R'S])FS"-L:(^&4(I"9IM=0I,A:A!6PF&!1&X,6PCB<
+M*4H%`Z]$,:)Q)8E!)31@,6OZ2A5@<)M"*@^BL04-:93@V$YZ$J2F3C%0L\+,
+M`<0FO!D8<CXHY8:SFV<`J27A)!'(X`P,YLP-#RKS#5"B,M#9#:"41K[<(J5)
+M'`B2QW"*<C)9B/4U@(*^`(,$!FP*I@:K;@%M`OF*ME/B!.(5XM$R`K5Z*9!_
+M-\B285-`QFBVZR4$72#.@A&@1C#OEE[FY'U9L]92'VR#C=*#GH1(3QE80ZPI
+=,+<O4!D:N9?-_F@8"(BA@F]_XNY(IPH2'F3A*&``
+`
+end