]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Support archive_read_data_block in archive_read_disk.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 10 Jun 2010 20:39:39 +0000 (16:39 -0400)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 10 Jun 2010 20:39:39 +0000 (16:39 -0400)
SVN-Revision: 2461

libarchive/archive_read_disk.c
libarchive/archive_read_disk_private.h
libarchive/test/test_read_disk_directory_traversals.c

index 1f94a42b5694a4c1aac7c050dc5e4d4ce2ebc5d0..32746b2a23eb3f78bac6b2992e9fb6ca12fbd863 100644 (file)
@@ -59,6 +59,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk.c 189429 2009-03-06 04
 #include "archive_private.h"
 #include "archive_read_disk_private.h"
 
+#ifndef O_BINARY
+#define O_BINARY       0
+#endif
+
 /*-
  * This is a new directory-walking system that addresses a number
  * of problems I've had with fts(3).  In particular, it has no
@@ -391,6 +395,7 @@ archive_read_disk_new(void)
        a->archive.vtable = archive_read_disk_vtable();
        a->lookup_uname = trivial_lookup_uname;
        a->lookup_gname = trivial_lookup_gname;
+       a->entry_fd = -1;
        return (&a->archive);
 }
 
@@ -398,29 +403,49 @@ static int
 _archive_read_free(struct archive *_a)
 {
        struct archive_read_disk *a = (struct archive_read_disk *)_a;
+       int r;
 
        if (_a == NULL)
                return (ARCHIVE_OK);
        archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
            ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free");
+
+       if (a->archive.state != ARCHIVE_STATE_CLOSED)
+               r = _archive_read_close(&a->archive);
+       else
+               r = ARCHIVE_OK;
+
        if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
                (a->cleanup_gname)(a->lookup_gname_data);
        if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
                (a->cleanup_uname)(a->lookup_uname_data);
        archive_string_free(&a->archive.error_string);
-       if (a->tree != NULL)
-               tree_close(a->tree);
+       free(a->entry_buff);
        a->archive.magic = 0;
        free(a);
-       return (ARCHIVE_OK);
+       return (r);
 }
 
 static int
 _archive_read_close(struct archive *_a)
 {
+       struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
        archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
            ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close");
-       (void)_a; /* UNUSED */
+
+       if (a->archive.state != ARCHIVE_STATE_FATAL)
+               a->archive.state = ARCHIVE_STATE_CLOSED;
+
+       if (a->tree != NULL) {
+               tree_close(a->tree);
+               a->tree = NULL;
+       }
+       if (a->entry_fd >= 0) {
+               close(a->entry_fd);
+               a->entry_fd = -1;
+       }
+
        return (ARCHIVE_OK);
 }
 
@@ -492,14 +517,81 @@ static int
 _archive_read_data_block(struct archive *_a, const void **buff,
     size_t *size, int64_t *offset)
 {
+       struct archive_read_disk *a = (struct archive_read_disk *)_a;
+       int r;
+       ssize_t bytes;
+       size_t buffbytes;
+
        archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
            "archive_read_data_block");
 
-       (void)buff; /* UNUSED */
-       (void)size; /* UNUSED */
-       (void)offset; /* UNUSED */
-       /* Not implemented yet. */
-       return (ARCHIVE_FAILED);
+       if (a->entry_eof || a->entry_remaining_bytes <= 0) {
+               r = ARCHIVE_EOF;
+               goto abort_read_data;
+       }
+
+       if (a->entry_fd < 0) {
+               a->entry_fd = open(tree_current_access_path(a->tree),
+                   O_RDONLY | O_BINARY);
+               if (a->entry_fd < 0) {
+                       archive_set_error(&a->archive, errno,
+                           "Couldn't open %s", tree_current_path(a->tree));
+                       r = ARCHIVE_FAILED;
+                       goto abort_read_data;
+               }
+       }
+       if (a->entry_buff == NULL) {
+               a->entry_buff = malloc(1024 * 64);
+               if (a->entry_buff == NULL) {
+                       archive_set_error(&a->archive, ENOMEM,
+                           "Couldn't allocate memory");
+                       r = ARCHIVE_FATAL;
+                       a->archive.state = ARCHIVE_STATE_FATAL;
+                       goto abort_read_data;
+               }
+               a->entry_buff_size = 1024 * 64;
+       }
+
+       buffbytes = a->entry_buff_size;
+       if ((int64_t)buffbytes > a->entry_remaining_bytes)
+               buffbytes = (size_t)a->entry_remaining_bytes;
+       bytes = read(a->entry_fd, a->entry_buff, buffbytes);
+       if (bytes < 0) {
+               archive_set_error(&a->archive, errno,
+                   "Read error");
+               r = ARCHIVE_FATAL;
+               a->archive.state = ARCHIVE_STATE_FATAL;
+               goto abort_read_data;
+       }
+       if (bytes == 0) {
+               /* Get EOF */
+               a->entry_eof = 1;
+               r = ARCHIVE_EOF;
+               goto abort_read_data;
+       }
+       *buff = a->entry_buff;
+       *size = bytes;
+       *offset = a->entry_total;
+       a->entry_total += bytes;
+       a->entry_remaining_bytes -= bytes;
+       if (a->entry_remaining_bytes == 0) {
+               /* Close the current file descriptor */
+               close(a->entry_fd);
+               a->entry_fd = -1;
+               a->entry_eof = 1;
+       }
+       return (ARCHIVE_OK);
+
+abort_read_data:
+       *buff = NULL;
+       *size = 0;
+       *offset = a->entry_total;
+       if (a->entry_fd >= 0) {
+               /* Close the current file descriptor */
+               close(a->entry_fd);
+               a->entry_fd = -1;
+       }
+       return (r);
 }
 
 static int
@@ -515,6 +607,10 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
            ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
            "archive_read_next_header2");
 
+       if (a->entry_fd >= 0) {
+               close(a->entry_fd);
+               a->entry_fd = -1;
+       }
        t = a->tree;
        st = NULL;
        lst = NULL;
@@ -604,9 +700,16 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
                a->archive.state = ARCHIVE_STATE_EOF;
                break;
        case ARCHIVE_OK:
-               a->archive.state = ARCHIVE_STATE_DATA;
-               break;
        case ARCHIVE_WARN:
+               a->entry_fd = -1;
+               a->entry_total = 0;
+               if (archive_entry_filetype(entry) == AE_IFREG) {
+                       a->entry_remaining_bytes = archive_entry_size(entry);
+                       a->entry_eof = (a->entry_remaining_bytes == 0)? 1: 0;
+               } else {
+                       a->entry_remaining_bytes = 0;
+                       a->entry_eof = 1;
+               }
                a->archive.state = ARCHIVE_STATE_DATA;
                break;
        case ARCHIVE_RETRY:
@@ -670,6 +773,8 @@ archive_read_disk_open(struct archive *_a, const char *pathname)
        tree->dev_recorded = 0;
        a->tree = tree;
        a->archive.state = ARCHIVE_STATE_HEADER;
+       a->entry_eof = 0;
+       a->entry_fd = -1;
 
        return (ARCHIVE_OK);
 }
index 42f6ce016d6639ffe94b7059905e616f69d1cfb3..fc4034becb6e07d2756b6b08e3aedbb064b51dd9 100644 (file)
@@ -55,6 +55,13 @@ struct archive_read_disk {
 
        struct tree *tree;
 
+       int              entry_fd;
+       int              entry_eof;
+       int64_t          entry_remaining_bytes;
+       int64_t          entry_total;
+       unsigned char   *entry_buff;
+       size_t           entry_buff_size;
+
 #if ARCHIVE_VERSION_NUMBER < 3000000
        const char * (*lookup_gname)(void *private, gid_t gid);
 #else
index 8734596d82fa1af1dcf541999d59203bff0a79f8..3b60c2ae3939c3f8ce4e16c76ac80b0f9f78f8a8 100644 (file)
@@ -29,13 +29,13 @@ DEFINE_TEST(test_read_disk_directory_traversals)
 {
        struct archive *a;
        struct archive_entry *ae;
-       //const void *p;
-       //size_t size;
-       //int64_t offset;
+       const void *p;
+       size_t size;
+       int64_t offset;
 
        assertMakeDir("dir1", 0755);
        assertMakeFile("dir1/file1", 0644, "0123456789");
-       assertMakeFile("dir1/file2", 0644, "0123456789");
+       assertMakeFile("dir1/file2", 0644, "hello world");
        assertMakeDir("dir1/sub1", 0755);
        assertMakeFile("dir1/sub1/file1", 0644, "0123456789");
        assertMakeDir("dir1/sub2", 0755);
@@ -44,7 +44,7 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        assertMakeDir("dir1/sub2/sub1", 0755);
        assertMakeDir("dir1/sub2/sub2", 0755);
        assertMakeDir("dir1/sub2/sub3", 0755);
-       assertMakeFile("dir1/sub2/sub3/file", 0644, "0123456789");
+       assertMakeFile("dir1/sub2/sub3/file", 0644, "xyz");
 
        assert((ae = archive_entry_new()) != NULL);
        assert((a = archive_read_disk_new()) != NULL);
@@ -63,20 +63,30 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        assertEqualString(archive_entry_pathname(ae), "dir1/file1");
        assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
        assertEqualInt(archive_entry_size(ae), 10);
-       //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
-       //assertEqualInt((int)size, 10);
-       //assertEqualInt((int)offset, 0);
-       //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 10);
+       assertEqualInt((int)offset, 0);
+       assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualInt(ARCHIVE_EOF,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 0);
+       assertEqualInt((int)offset, 10);
 
        /* dir1/file2 */
        assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
        assertEqualString(archive_entry_pathname(ae), "dir1/file2");
        assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
-       assertEqualInt(archive_entry_size(ae), 10);
-       //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
-       //assertEqualInt((int)size, 10);
-       //assertEqualInt((int)offset, 0);
-       //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualInt(archive_entry_size(ae), 11);
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 11);
+       assertEqualInt((int)offset, 0);
+       assertEqualInt(memcmp(p, "hello world", 11), 0);
+       assertEqualInt(ARCHIVE_EOF,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 0);
+       assertEqualInt((int)offset, 11);
 
        /* dir1/sub1 */
        assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
@@ -99,20 +109,30 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        assertEqualString(archive_entry_pathname(ae), "dir1/sub2/file1");
        assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
        assertEqualInt(archive_entry_size(ae), 10);
-       //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
-       //assertEqualInt((int)size, 10);
-       //assertEqualInt((int)offset, 0);
-       //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 10);
+       assertEqualInt((int)offset, 0);
+       assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualInt(ARCHIVE_EOF,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 0);
+       assertEqualInt((int)offset, 10);
 
        /* dir1/sub2/file2 */
        assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
        assertEqualString(archive_entry_pathname(ae), "dir1/sub2/file2");
        assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
        assertEqualInt(archive_entry_size(ae), 10);
-       //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
-       //assertEqualInt((int)size, 10);
-       //assertEqualInt((int)offset, 0);
-       //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 10);
+       assertEqualInt((int)offset, 0);
+       assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualInt(ARCHIVE_EOF,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 0);
+       assertEqualInt((int)offset, 10);
 
        /* dir1/sub2/sub1 */
        assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
@@ -142,21 +162,31 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
        assertEqualString(archive_entry_pathname(ae), "dir1/sub2/sub3/file");
        assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
-       assertEqualInt(archive_entry_size(ae), 10);
-       //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
-       //assertEqualInt((int)size, 10);
-       //assertEqualInt((int)offset, 0);
-       //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualInt(archive_entry_size(ae), 3);
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 3);
+       assertEqualInt((int)offset, 0);
+       assertEqualInt(memcmp(p, "xyz", 3), 0);
+       assertEqualInt(ARCHIVE_EOF,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 0);
+       assertEqualInt((int)offset, 3);
 
        /* dir1/sub1/file1 */
        assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
        assertEqualString(archive_entry_pathname(ae), "dir1/sub1/file1");
        assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
        assertEqualInt(archive_entry_size(ae), 10);
-       //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
-       //assertEqualInt((int)size, 10);
-       //assertEqualInt((int)offset, 0);
-       //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 10);
+       assertEqualInt((int)offset, 0);
+       assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualInt(ARCHIVE_EOF,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 0);
+       assertEqualInt((int)offset, 10);
 
        /* There is no entry. */
        assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
@@ -176,10 +206,11 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        assertEqualString(archive_entry_pathname(ae), "dir1/file1");
        assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
        assertEqualInt(archive_entry_size(ae), 10);
-       //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
-       //assertEqualInt((int)size, 10);
-       //assertEqualInt((int)offset, 0);
-       //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 10);
+       assertEqualInt((int)offset, 0);
+       assertEqualInt(memcmp(p, "0123456789", 10), 0);
 
        /* There is no entry. */
        assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
@@ -201,10 +232,11 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        assertEqualString(archive_entry_pathname(ae), "dir1/file1");
        assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
        assertEqualInt(archive_entry_size(ae), 10);
-       //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
-       //assertEqualInt((int)size, 10);
-       //assertEqualInt((int)offset, 0);
-       //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 10);
+       assertEqualInt((int)offset, 0);
+       assertEqualInt(memcmp(p, "0123456789", 10), 0);
 
        /* dir1/sub1 */
        assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
@@ -219,10 +251,11 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        assertEqualString(archive_entry_pathname(ae), "dir1/sub1/file1");
        assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
        assertEqualInt(archive_entry_size(ae), 10);
-       //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
-       //assertEqualInt((int)size, 10);
-       //assertEqualInt((int)offset, 0);
-       //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_data_block(a, &p, &size, &offset));
+       assertEqualInt((int)size, 10);
+       assertEqualInt((int)offset, 0);
+       assertEqualInt(memcmp(p, "0123456789", 10), 0);
 
        /* There is no entry. */
        assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));