]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Improve handling of Rockridge extensions' rr_moved directory and
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 15 Oct 2009 11:37:18 +0000 (07:37 -0400)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 15 Oct 2009 11:37:18 +0000 (07:37 -0400)
following sub directories.
Add corresponding test.
Unfortunately, some tests need tweaks due to difference of ordering of
hardlink files(which have the same offset); it's characteristic of heap.

SVN-Revision: 1529

12 files changed:
Makefile.am
libarchive/archive_read_support_format_iso9660.c
libarchive/test/CMakeLists.txt
libarchive/test/Makefile
libarchive/test/test_read_format_isojoliet_bz2.c
libarchive/test/test_read_format_isojoliet_long.c
libarchive/test/test_read_format_isojoliet_rr.c
libarchive/test/test_read_format_isorr_bz2.c
libarchive/test/test_read_format_isorr_new_bz2.c
libarchive/test/test_read_format_isorr_rr_moved.c [new file with mode: 0644]
libarchive/test/test_read_format_isorr_rr_moved.iso.bz2.uu [new file with mode: 0644]
libarchive/test/test_read_format_isozisofs_bz2.c

index 2fcf62aa11be0b295cb059764a3a1f9863f0299b..b14cf4585f7ad2804b559cc401b13c5de41f0857 100644 (file)
@@ -263,6 +263,7 @@ libarchive_test_SOURCES=                                    \
        libarchive/test/test_read_format_isorr_bz2.c            \
        libarchive/test/test_read_format_isorr_ce.c             \
        libarchive/test/test_read_format_isorr_new_bz2.c        \
+       libarchive/test/test_read_format_isorr_rr_moved.c       \
        libarchive/test/test_read_format_isozisofs_bz2.c        \
        libarchive/test/test_read_format_mtree.c                \
        libarchive/test/test_read_format_pax_bz2.c              \
@@ -347,6 +348,7 @@ libarchive_test_EXTRA_DIST=\
        libarchive/test/test_read_format_isorr_bz2.iso.bz2.uu           \
        libarchive/test/test_read_format_isorr_ce.iso.bz2.uu            \
        libarchive/test/test_read_format_isorr_new_bz2.iso.bz2.uu       \
+       libarchive/test/test_read_format_isorr_rr_moved.iso.bz2.uu      \
        libarchive/test/test_read_format_isozisofs_bz2.iso.bz2.uu       \
        libarchive/test/test_read_format_raw.data.Z.uu                  \
        libarchive/test/test_read_format_raw.data.uu                    \
index 0a19d560eb39c57a22600bf735db22e801fd00f6..9809ec34e2af04939877fdf129ba15f54a236a55 100644 (file)
@@ -250,12 +250,15 @@ struct zisofs {
 /* In-memory storage for a directory record. */
 struct file_info {
        struct file_info        *parent;
+       struct file_info        *next;
        int              refcount;
        int              subdirs;
        uint64_t         offset;        /* Offset on disk.              */
        uint64_t         size;          /* File size in bytes.          */
        uint32_t         ce_offset;     /* Offset of CE.                */
        uint32_t         ce_size;       /* Size of CE.                  */
+       char             re;            /* Having RRIP "RE" extension.  */
+       uint64_t         cl_offset;     /* Having RRIP "CL" extension.  */
        time_t           birthtime;     /* File created time.           */
        time_t           mtime;         /* File last modified time.     */
        time_t           atime;         /* File last accessed time.     */
@@ -290,6 +293,15 @@ struct iso9660 {
        char    seenJoliet;
 
        unsigned char   suspOffset;
+       struct file_info *rr_moved;
+       struct {
+               struct file_info        *first;
+               struct file_info        **last;
+       } re_dirs;
+       struct {
+               struct file_info        *first;
+               struct file_info        **last;
+       } cl_files;
        struct {
                struct read_ce_req {
                        uint64_t         offset;/* Offset of CE on disk. */
@@ -298,6 +310,7 @@ struct iso9660 {
                int              cnt;
                int              allocated;
        }       read_ce_req;
+
        int64_t         previous_number;
        uint64_t        previous_size;
        struct archive_string previous_pathname;
@@ -312,6 +325,11 @@ struct iso9660 {
                int                      count;
                int                      index;
        }       cache_files;
+       struct {
+               struct file_info        *first;
+               struct file_info        **last;
+       } pending_dirs;
+       int     read_pending_dirs;
 
        uint64_t current_position;
        ssize_t logical_block_size;
@@ -391,6 +409,12 @@ archive_read_support_format_iso9660(struct archive *_a)
        }
        memset(iso9660, 0, sizeof(*iso9660));
        iso9660->magic = ISO9660_MAGIC;
+       iso9660->pending_dirs.first = NULL;
+       iso9660->pending_dirs.last = &(iso9660->pending_dirs.first);
+       iso9660->re_dirs.first = NULL;
+       iso9660->re_dirs.last = &(iso9660->re_dirs.first);
+       iso9660->cl_files.first = NULL;
+       iso9660->cl_files.last = &(iso9660->cl_files.first);
        /* Enable to support Joliet extensions by default.      */
        iso9660->opt_support_joliet = 1;
        /* Enable to support Rock Ridge extensions by default.  */
@@ -719,6 +743,29 @@ read_children(struct archive_read *a, struct file_info *parent)
        size_t step;
 
        iso9660 = (struct iso9660 *)(a->format->data);
+       if (iso9660->current_position > parent->offset) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Ignoring out-of-order directory (%s) %jd > %jd",
+                   parent->name.s,
+                   iso9660->current_position,
+                   parent->offset);
+               return (ARCHIVE_WARN);
+       }
+       if (parent->offset + parent->size > iso9660->volume_size) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Directory is beyond end-of-media: %s",
+                   parent->name);
+               return (ARCHIVE_WARN);
+       }
+       if (iso9660->current_position < parent->offset) {
+               int64_t skipsize;
+
+               skipsize = parent->offset - iso9660->current_position;
+               skipsize = __archive_read_skip(a, skipsize);
+               if (skipsize < 0)
+                       return ((int)skipsize);
+               iso9660->current_position = parent->offset;
+       }
 
        step = ((parent->size + iso9660->logical_block_size -1) /
            iso9660->logical_block_size) * iso9660->logical_block_size;
@@ -754,9 +801,110 @@ read_children(struct archive_read *a, struct file_info *parent)
                        child = parse_file_info(a, parent, p);
                        if (child == NULL)
                                return (ARCHIVE_FATAL);
-                       add_entry(iso9660, child);
+                       if (child->cl_offset) {
+                               child->next = NULL;
+                               *iso9660->cl_files.last = child;
+                               iso9660->cl_files.last = &(child->next);
+                       } else
+                               add_entry(iso9660, child);
+               }
+       }
+
+       /* Read data which recorded by RRIP "CE" extension. */
+       if (read_CE(a, iso9660) != ARCHIVE_OK)
+               return (ARCHIVE_FATAL);
+
+       return (ARCHIVE_OK);
+}
+
+static int
+relocate_dir(struct iso9660 *iso9660, struct file_info *file)
+{
+       struct file_info **cl;
+       struct file_info *tmp;
+
+       for (cl = &iso9660->re_dirs.first; *cl != NULL;
+           cl = &((*cl)->next)) {
+               if ((*cl)->offset == file->cl_offset) {
+                       tmp = *cl;
+                       (*cl)->parent->refcount--;
+                       file->parent->refcount++;
+                       file->parent->subdirs++;
+                       (*cl)->parent = file->parent;
+                       *cl = (*cl)->next;
+                       iso9660->rr_moved->subdirs--;
+                       tmp->next = NULL;
+                       tmp->refcount++;
+                       *iso9660->pending_dirs.last = tmp;
+                       iso9660->pending_dirs.last = &(tmp->next);
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+static int
+read_entries(struct archive_read *a)
+{
+       struct iso9660 *iso9660;
+       struct file_info *file;
+       int r;
+
+       iso9660 = (struct iso9660 *)(a->format->data);
+
+       while ((file = next_entry(iso9660)) != NULL &&
+           (file->mode & AE_IFMT) == AE_IFDIR) {
+               r = read_children(a, file);
+               if (r != ARCHIVE_OK)
+                       return (r);
+
+               if (iso9660->seenRockridge &&
+                   file->parent != NULL &&
+                   file->parent->parent == NULL &&
+                   iso9660->rr_moved == NULL &&
+                   (strcmp(file->name.s, "rr_moved") == 0 ||
+                    strcmp(file->name.s, ".rr_moved") == 0)) {
+                       iso9660->rr_moved = file;
+               } else if (file->re) {
+                       file->next = NULL;
+                       *iso9660->re_dirs.last = file;
+                       iso9660->re_dirs.last = &(file->next);
+               } else {
+                       file->next = NULL;
+                       file->refcount++;
+                       *iso9660->pending_dirs.last = file;
+                       iso9660->pending_dirs.last = &(file->next);
+               }
+       }
+       if (file != NULL)
+               add_entry(iso9660, file);
+
+       if (iso9660->rr_moved != NULL) {
+               struct file_info *next;
+
+               /*
+                * Relocate directory which rr_moved has.
+                */
+               for (file = iso9660->cl_files.first; file != NULL;
+                   file = next) {
+                       next = file->next;
+
+                       relocate_dir(iso9660, file);
+                       release_file(iso9660, file);
+               }
+
+               /* If rr_moved directory still has children,
+                * Add rr_moved into pending_files to show
+                */
+               if (iso9660->rr_moved->subdirs)
+                       add_entry(iso9660, iso9660->rr_moved);
+               else {
+                       iso9660->rr_moved->parent->subdirs--;
+                       release_file(iso9660, iso9660->rr_moved);
                }
        }
+       iso9660->read_pending_dirs = 1;
+
        return (ARCHIVE_OK);
 }
 
@@ -766,7 +914,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
 {
        struct iso9660 *iso9660;
        struct file_info *file;
-       int r;
+       int r, rd_r;
 
        iso9660 = (struct iso9660 *)(a->format->data);
 
@@ -857,7 +1005,11 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
                        a->archive.archive_format_name =
                            "ISO9660 with Rockridge extensions";
                }
-       }
+               rd_r = read_entries(a);
+               if (rd_r == ARCHIVE_FATAL)
+                       return (ARCHIVE_FATAL);
+       } else
+               rd_r = ARCHIVE_OK;
 
        /* Get the next entry that appears after the current offset. */
        r = next_entry_seek(a, iso9660, &file);
@@ -927,7 +1079,8 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
         * will give us support for whacky ISO images that require
         * seeking while retaining the ability to read almost all ISO
         * images in a streaming fashion. */
-       if (file->offset < iso9660->current_position) {
+       if ((file->mode & AE_IFMT) != AE_IFDIR &&
+           file->offset < iso9660->current_position) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                    "Ignoring out-of-order file @%x (%s) %jd < %jd",
                    file,
@@ -961,13 +1114,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
        iso9660->previous_number = file->number;
        archive_strcpy(&iso9660->previous_pathname, iso9660->pathname.s);
 
-       /* If this is a directory, read in all of the entries right now. */
        if (archive_entry_filetype(entry) == AE_IFDIR) {
-               r = read_children(a, file);
-               if (r != ARCHIVE_OK) {
-                       release_file(iso9660, file);
-                       return (ARCHIVE_FATAL);
-               }
                /* Overwrite nlinks by proper link number which is
                 * calculated from number of sub directories. */
                archive_entry_set_nlink(entry, 2 + file->subdirs);
@@ -977,6 +1124,9 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
        }
 
        release_file(iso9660, file);
+
+       if (rd_r != ARCHIVE_OK)
+               return (rd_r);
        return (ARCHIVE_OK);
 }
 
@@ -1486,7 +1636,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
        }
 
        /* Tell file's parent how many children that parent has. */
-       if (parent != NULL && (flags & 0x02))
+       if (parent != NULL && (flags & 0x02) && file->cl_offset == 0)
                parent->subdirs++;
 
 #if DEBUG
@@ -1544,6 +1694,7 @@ add_entry(struct iso9660 *iso9660, struct file_info *file)
        }
 
        file_offset = file->offset + file->size;
+       file->refcount++;
 
        /*
         * Start with hole at end, walk it up tree to find insertion point.
@@ -1572,7 +1723,7 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
 
        iso9660 = (struct iso9660 *)(a->format->data);
 
-       while (p + 4 < end  /* Enough space for another entry. */
+       while (p + 4 <= end  /* Enough space for another entry. */
            && p[0] >= 'A' && p[0] <= 'Z' /* Sanity-check 1st char of name. */
            && p[1] >= 'A' && p[1] <= 'Z' /* Sanity-check 2nd char of name. */
            && p[2] >= 4 /* Sanity-check length. */
@@ -1608,6 +1759,15 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
                                }
                                break;
                        }
+                       if (p[0] == 'C' && p[1] == 'L') {
+                               if (version == 1 && data_length == 8) {
+                                       file->cl_offset = (uint64_t)
+                                           iso9660->logical_block_size *
+                                           (uint64_t)archive_le32dec(data);
+                                       iso9660->seenRockridge = 1;
+                               }
+                               break;
+                       }
                        /* FALLTHROUGH */
                case 'N':
                        if (p[0] == 'N' && p[1] == 'M') {
@@ -1667,6 +1827,11 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
                        }
                        /* FALLTHROUGH */
                case 'R':
+                       if (p[0] == 'R' && p[1] == 'E' && version == 1) {
+                               file->re = 1;
+                               iso9660->seenRockridge = 1;
+                               break;
+                       }
                        if (p[0] == 'R' && p[1] == 'R' && version == 1) {
                                /*
                                 * RR extension comprises:
@@ -2077,10 +2242,6 @@ next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
        if (file == NULL)
                return (ARCHIVE_EOF);
 
-       /* Read data which recorded by RRIP "CE" extension. */
-       if (read_CE(a, iso9660) != ARCHIVE_OK)
-               return (ARCHIVE_FATAL);
-
        /* Don't waste time seeking for zero-length bodies. */
        if (file->size == 0)
                file->offset = iso9660->current_position;
@@ -2162,6 +2323,17 @@ next_entry(struct iso9660 *iso9660)
        int a, b, c;
        struct file_info *r, *tmp;
 
+       if (iso9660->read_pending_dirs) {
+               
+               r = iso9660->pending_dirs.first;
+               if (r != NULL) {
+                       iso9660->pending_dirs.first = r->next;
+                       r->refcount--;
+                       return (r);
+               } else
+                       iso9660->read_pending_dirs = 0;
+       }
+
        if (iso9660->pending_files_used < 1)
                return (NULL);
 
@@ -2169,6 +2341,7 @@ next_entry(struct iso9660 *iso9660)
         * The first file in the list is the earliest; we'll return this.
         */
        r = iso9660->pending_files[0];
+       r->refcount--;
 
        /*
         * Move the last item in the heap to the root of the tree
index 66b98bd37bdd6bbeb86d30b038b5d781899f43ab..7619150bc9d38dd36cecc14724742b8e0d6ac52b 100644 (file)
@@ -62,6 +62,7 @@ IF(ENABLE_TEST)
     test_read_format_isorr_bz2.c
     test_read_format_isorr_ce.c
     test_read_format_isorr_new_bz2.c
+    test_read_format_isorr_rr_moved.c
     test_read_format_isozisofs_bz2.c
     test_read_format_mtree.c
     test_read_format_pax_bz2.c
index 4f70859b83dfe2fc46610e1fb3be22d947952308..2ef1e1b34f626a2d8ab96398802818f9a9b0424f 100644 (file)
@@ -57,6 +57,7 @@ TESTS= \
        test_read_format_isorr_bz2.c            \
        test_read_format_isorr_ce.c             \
        test_read_format_isorr_new_bz2.c        \
+       test_read_format_isorr_rr_moved.c       \
        test_read_format_isozisofs_bz2.c        \
        test_read_format_mtree.c                \
        test_read_format_pax_bz2.c              \
index 996ecbeb5be5b8a1838c2e0a992ba2b060c6ecc5..5e89874f3e20d3083d2148aac718e74320eff82a 100644 (file)
@@ -101,7 +101,8 @@ DEFINE_TEST(test_read_format_isojoliet_bz2)
        /* A regular file with two names ("hardlink" gets returned
         * first, so it's not marked as a hardlink). */
        assertEqualInt(0, archive_read_next_header(a, &ae));
-       assertEqualString("hardlink", archive_entry_pathname(ae));
+       assertEqualString("long-joliet-file-name.textfile",
+           archive_entry_pathname(ae));
        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
        assert(archive_entry_hardlink(ae) == NULL);
        assertEqualInt(6, archive_entry_size(ae));
@@ -113,10 +114,10 @@ DEFINE_TEST(test_read_format_isojoliet_bz2)
        /* Second name for the same regular file (this happens to be
         * returned second, so does get marked as a hardlink). */
        assertEqualInt(0, archive_read_next_header(a, &ae));
-       assertEqualString("long-joliet-file-name.textfile",
-           archive_entry_pathname(ae));
+       assertEqualString("hardlink", archive_entry_pathname(ae));
        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
-       assertEqualString("hardlink", archive_entry_hardlink(ae));
+       assertEqualString("long-joliet-file-name.textfile",
+           archive_entry_hardlink(ae));
        assert(!archive_entry_size_is_set(ae));
 
        /* A symlink to the regular file. */
index 3df774cba137bb706daa3fff8e20549513708fa6..81c1b5f2263c723df9602b985ca06b9115af055e 100644 (file)
@@ -109,10 +109,14 @@ DEFINE_TEST(test_read_format_isojoliet_long)
        assertEqualInt(86401, archive_entry_mtime(ae));
        assertEqualInt(86401, archive_entry_atime(ae));
 
-       /* A regular file with two names ("hardlink" gets returned
+       /* A regular file with two names (pathname gets returned
         * first, so it's not marked as a hardlink). */
+       pathname[100] = '1';
+       pathname[101] = '2';
+       pathname[102] = '3';
+       pathname[103] = '\0';
        assertEqualInt(0, archive_read_next_header(a, &ae));
-       assertEqualString("hardlink", archive_entry_pathname(ae));
+       assertEqualString(pathname, archive_entry_pathname(ae));
        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
        assert(archive_entry_hardlink(ae) == NULL);
        assertEqualInt(6, archive_entry_size(ae));
@@ -123,14 +127,10 @@ DEFINE_TEST(test_read_format_isojoliet_long)
 
        /* Second name for the same regular file (this happens to be
         * returned second, so does get marked as a hardlink). */
-       pathname[100] = '1';
-       pathname[101] = '2';
-       pathname[102] = '3';
-       pathname[103] = '\0';
        assertEqualInt(0, archive_read_next_header(a, &ae));
-       assertEqualString(pathname, archive_entry_pathname(ae));
+       assertEqualString("hardlink", archive_entry_pathname(ae));
        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
-       assertEqualString("hardlink", archive_entry_hardlink(ae));
+       assertEqualString(pathname, archive_entry_hardlink(ae));
        assert(!archive_entry_size_is_set(ae));
 
        /* End of archive. */
index 3a5604729797e5c23992baaa8435d5e80e7ba7ab..e3ab2e3eab4589af68643aabb014dfa9e7f1946c 100644 (file)
@@ -104,7 +104,8 @@ DEFINE_TEST(test_read_format_isojoliet_rr)
        /* A regular file with two names ("hardlink" gets returned
         * first, so it's not marked as a hardlink). */
        assertEqualInt(0, archive_read_next_header(a, &ae));
-       assertEqualString("hardlink", archive_entry_pathname(ae));
+       assertEqualString("long-joliet-file-name.textfile",
+           archive_entry_pathname(ae));
        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
        assert(archive_entry_hardlink(ae) == NULL);
        assertEqualInt(6, archive_entry_size(ae));
@@ -125,10 +126,10 @@ DEFINE_TEST(test_read_format_isojoliet_rr)
        /* Second name for the same regular file (this happens to be
         * returned second, so does get marked as a hardlink). */
        assertEqualInt(0, archive_read_next_header(a, &ae));
-       assertEqualString("long-joliet-file-name.textfile",
-           archive_entry_pathname(ae));
+       assertEqualString("hardlink", archive_entry_pathname(ae));
        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
-       assertEqualString("hardlink", archive_entry_hardlink(ae));
+       assertEqualString("long-joliet-file-name.textfile",
+           archive_entry_hardlink(ae));
        assert(!archive_entry_size_is_set(ae));
        assertEqualInt(86401, archive_entry_mtime(ae));
        assertEqualInt(86401, archive_entry_atime(ae));
index 7a3cd0a1c279674ef7665f54be5ce6013a5549f8..549c9500613ff3b25f20349c510e39df5e45305f 100644 (file)
@@ -104,9 +104,9 @@ DEFINE_TEST(test_read_format_isorr_bz2)
                        assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
                        assertEqualInt(1, archive_entry_uid(ae));
                        assertEqualInt(2, archive_entry_gid(ae));
-               } else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
+               } else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
                        /* A regular file. */
-                       assertEqualString("file", archive_entry_pathname(ae));
+                       assertEqualString("hardlink", archive_entry_pathname(ae));
                        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
                        assertEqualInt(12345684, archive_entry_size(ae));
                        assertEqualInt(0,
@@ -118,16 +118,16 @@ DEFINE_TEST(test_read_format_isorr_bz2)
                        assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
                        assertEqualInt(1, archive_entry_uid(ae));
                        assertEqualInt(2, archive_entry_gid(ae));
-               } else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
+               } else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
                        /* A hardlink to the regular file. */
                        /* Note: If "hardlink" gets returned before "file",
                         * then "hardlink" will get returned as a regular file
                         * and "file" will get returned as the hardlink.
                         * This test should tolerate that, since it's a
                         * perfectly permissible thing for libarchive to do. */
-                       assertEqualString("hardlink", archive_entry_pathname(ae));
+                       assertEqualString("file", archive_entry_pathname(ae));
                        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
-                       assertEqualString("file", archive_entry_hardlink(ae));
+                       assertEqualString("hardlink", archive_entry_hardlink(ae));
                        assertEqualInt(0, archive_entry_size_is_set(ae));
                        assertEqualInt(0, archive_entry_size(ae));
                        assertEqualInt(86401, archive_entry_mtime(ae));
index 18170e4ecc7dc504ea2f97580a710b53bf7a7401..bc460cda667c2aacbb014c50ed80351c26fe5cf8 100644 (file)
@@ -103,9 +103,9 @@ DEFINE_TEST(test_read_format_isorr_new_bz2)
                        assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
                        assertEqualInt(1, archive_entry_uid(ae));
                        assertEqualInt(2, archive_entry_gid(ae));
-               } else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
+               } else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
                        /* A regular file. */
-                       assertEqualString("file", archive_entry_pathname(ae));
+                       assertEqualString("hardlink", archive_entry_pathname(ae));
                        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
                        assertEqualInt(12345684, archive_entry_size(ae));
                        assertEqualInt(0,
@@ -117,16 +117,16 @@ DEFINE_TEST(test_read_format_isorr_new_bz2)
                        assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
                        assertEqualInt(1, archive_entry_uid(ae));
                        assertEqualInt(2, archive_entry_gid(ae));
-               } else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
+               } else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
                        /* A hardlink to the regular file. */
                        /* Note: If "hardlink" gets returned before "file",
                         * then "hardlink" will get returned as a regular file
                         * and "file" will get returned as the hardlink.
                         * This test should tolerate that, since it's a
                         * perfectly permissible thing for libarchive to do. */
-                       assertEqualString("hardlink", archive_entry_pathname(ae));
+                       assertEqualString("file", archive_entry_pathname(ae));
                        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
-                       assertEqualString("file", archive_entry_hardlink(ae));
+                       assertEqualString("hardlink", archive_entry_hardlink(ae));
                        assertEqualInt(0, archive_entry_size_is_set(ae));
                        assertEqualInt(0, archive_entry_size(ae));
                        assertEqualInt(86401, archive_entry_mtime(ae));
diff --git a/libarchive/test/test_read_format_isorr_rr_moved.c b/libarchive/test/test_read_format_isorr_rr_moved.c
new file mode 100644 (file)
index 0000000..d17b87f
--- /dev/null
@@ -0,0 +1,276 @@
+/*-
+ * 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"
+
+/*
+Execute the following command to rebuild the data for this program:
+   tail -n +32 test_read_format_isorr_rr_moved.c | /bin/sh
+
+dirname=/tmp/iso
+rm -rf $dirname
+mkdir -p $dirname/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/dir9/dir10
+echo "hello" >$dirname/file
+dd if=/dev/zero count=1 bs=12345678 >>$dirname/file
+deepfile=$dirname/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/dir9/dir10/deep
+echo "hello" >$deepfile
+dd if=/dev/zero count=1 bs=12345678 >>$deepfile
+time="197001020000.01"
+TZ=utc touch -afhm -t $time $deepfile
+TZ=utc touch -afhm -t $time $dirname/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/dir9/dir10
+TZ=utc touch -afhm -t $time $dirname/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/dir9
+TZ=utc touch -afhm -t $time $dirname/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8
+TZ=utc touch -afhm -t $time $dirname/dir1/dir2/dir3/dir4/dir5/dir6/dir7
+TZ=utc touch -afhm -t $time $dirname/dir1/dir2/dir3/dir4/dir5/dir6
+TZ=utc touch -afhm -t $time $dirname/dir1/dir2/dir3/dir4/dir5
+TZ=utc touch -afhm -t $time $dirname/dir1/dir2/dir3/dir4
+TZ=utc touch -afhm -t $time $dirname/dir1/dir2/dir3
+TZ=utc touch -afhm -t $time $dirname/dir1/dir2
+TZ=utc touch -afhm -t $time $dirname/dir1
+TZ=utc touch -afhm -t $time $dirname/file
+TZ=utc touch -afhm -t $time $dirname
+F=test_read_format_isorr_rr_moved.iso.bz2
+mkhybrid -R -uid 1 -gid 2 $dirname | bzip2 > $F
+uuencode $F $F > $F.uu
+exit 1
+ */
+
+DEFINE_TEST(test_read_format_isorr_rr_moved)
+{
+       const char *refname = "test_read_format_isorr_rr_moved.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 8 files on the ISO image and
+        * verify that each one is what we expect. */
+       for (i = 0; i < 13; ++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));
+                       /* Now, we read timestamp recorded by RRIP "TF". */
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(0, archive_entry_mtime_nsec(ae));
+                       /* Now, we read links recorded by RRIP "PX". */
+                       assertEqualInt(3, 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("dir1", archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1", archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(3, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } else if (strcmp("dir1/dir2",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1/dir2",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(3, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } else if (strcmp("dir1/dir2/dir3",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1/dir2/dir3",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(3, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } else if (strcmp("dir1/dir2/dir3/dir4",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1/dir2/dir3/dir4",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(3, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } else if (strcmp("dir1/dir2/dir3/dir4/dir5",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1/dir2/dir3/dir4/dir5",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(3, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } else if (strcmp("dir1/dir2/dir3/dir4/dir5/dir6",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1/dir2/dir3/dir4/dir5/dir6",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(3, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } else if (strcmp("dir1/dir2/dir3/dir4/dir5/dir6/dir7",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1/dir2/dir3/dir4/dir5/dir6/dir7",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(3, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } else if (strcmp("dir1/dir2/dir3/dir4/dir5/dir6/dir7"
+                  "/dir8",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1/dir2/dir3/dir4/dir5/dir6/dir7"
+                           "/dir8",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(3, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } else if (strcmp("dir1/dir2/dir3/dir4/dir5/dir6/dir7"
+                  "/dir8/dir9",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1/dir2/dir3/dir4/dir5/dir6/dir7"
+                           "/dir8/dir9",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(3, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } else if (strcmp("dir1/dir2/dir3/dir4/dir5/dir6/dir7"
+                  "/dir8/dir9/dir10",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A directory. */
+                       assertEqualString("dir1/dir2/dir3/dir4/dir5/dir6/dir7"
+                           "/dir8/dir9/dir10",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
+                       assertEqualInt(2048, archive_entry_size(ae));
+                       assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
+                       assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
+                       assertEqualInt(1, archive_entry_uid(ae));
+                       assertEqualInt(2, archive_entry_gid(ae));
+               } 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(12345684, archive_entry_size(ae));
+                       assertEqualInt(0,
+                           archive_read_data_block(a, &p, &size, &offset));
+                       assertEqualInt(0, offset);
+                       assertEqualMem(p, "hello\n", 6);
+                       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 if (strcmp("dir1/dir2/dir3/dir4/dir5/dir6/dir7"
+                   "/dir8/dir9/dir10/deep",
+                   archive_entry_pathname(ae)) == 0) {
+                       /* A regular file. */
+                       assertEqualString("dir1/dir2/dir3/dir4/dir5/dir6/dir7"
+                           "/dir8/dir9/dir10/deep",
+                           archive_entry_pathname(ae));
+                       assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
+                       assertEqualInt(12345684, archive_entry_size(ae));
+                       assertEqualInt(0,
+                           archive_read_data_block(a, &p, &size, &offset));
+                       assertEqualInt(0, offset);
+                       assertEqualMem(p, "hello\n", 6);
+                       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_isorr_rr_moved.iso.bz2.uu b/libarchive/test/test_read_format_isorr_rr_moved.iso.bz2.uu
new file mode 100644 (file)
index 0000000..039f2fe
--- /dev/null
@@ -0,0 +1,34 @@
+begin 644 test_read_format_isorr_rr_moved.iso.bz2
+M0EIH.3%!62936>2O?C\``<!_____&__]9__X/__?8*_GWY<AJ$0P9%P@)2`@
+MA````L`(T`5^`V8.2:SEVTW,VX&BGZ4TFE/*>0F1Y$\4R>B:/4>34:>ID;2;
+M0"#!-!AJ,1IH]3U!IZ3(8`T),-$4\4]%/34!Z:(#0`T`T#0``&0&33#2````
+M$FJ2$])&30:;4:-J&0```#0``:`#0``T``'J`@P`$P`!,```````````````
+M`$2B*8333(4]HT&I-DT3)Z$&F@-#U!Z@``T#08@`&@'J>IZET$*:93.+D72Y
+MO@@AV2Z`E\!,\`+A?0R#K+KCE#8'9':';',/*'NTY>X?9Q<>*WF;((?]%DXX
+M"E&$03!`%UH(:F"L`J=&!\D1#JD4$3CB""(*IO0$40ERBX;KDRZV$`!T+NM5
+MRZ],NE0$,N6BH"``#M`!(PEZA`$@@#(@K_A$00``'%%$YJ(F+%554Q1Q3P))
+MC@8X8YCSX]L5A"NNN(555558"A[WO>^*R61SD"`J@D#@9^[S(YD^AL]MB+,\
+MD.)/VH$$/OD$$D@DD$D@DPA@S,22'+24!`'4;QU&-.I4.FR``0WJCF5`/'Y,
+M:KY/E=#@X#AOJZ#OB4R%,T0I(2%D4RP-N**JJJGW_N:N4@FP0$SR5.ZN6="B
+M"=RNA6VJE)TMJ*=;/+1&T&@H>HB)47Q=\4-TT+$1-.70?SIPFX"$-ZA00+YG
+M"AC!#.T"""U1$H%$(P8Q8P80(P8P6)&)&)&)$2*"_XI9F8,A+%0`.1D4QKNF
+MJQ\>V5UV:ZZZJZZ6S*,"5,C-2.62!52&72D@(;9$0YD*W41.N#Y!933!`PUS
+MH>-US<!`N6BAF!`\WI^%>XB)A"M"B$2,(]$(`RNJ4!$C&(S5$@,H(B"#$8Z&
+MDI&(D8Q$C&(D8RU2D:&U0Q<#UL'P^@K*@E"&9*,W=_+VH#-KR).I&BE[X1]S
+M:<RHKYQ:^.[:M:CO4\+B85J^S5G23R7T,6518L2[0HB/;"`)4E?00JP4YU*0
+M5D)0A1&-A1"BI(0D%)"&<X34%"FK##@IF-K-OV_.3VM3%?O8[Q8'3.\1Y-(P
+M@&"#R-`$$4!BE$&[+VI-,3R33,.=H!SR;#?)31MVEH5%)2KHX9.:TJ@-J`QA
+M&9/U(33$B(!$!"CB"PT9:VX,&F=0\00.>9.UO;,F?RJUU@0[9]>/G=H[IJ]I
+M[<G2Q$C4V5P*M#MAD,&];)XLJ)WUBKZ)'4<N6U,O!5QT3+1-R@[C"[#$@D](
+MT<,)59L+!;V37&N2BH=PHXM\(D3B:]O\6%_2L,:`=M';4BI"HH731V('4P9K
+MU2<[%J&L9R,MLK5N9S=HPL)KQ:-P8*``!,)HSI/*Z#Q*[+YAAQU0C;`1'K29
+M39;^7%*IT",.H^8`_WV0D<'-GM47$N);0!F#\M5#RW(=6=U4-L>EA/3%B/W"
+MI'46,VE:Q&3^U'ABINDR4R4WZ=-.$G,;:86(2!B7?<E(E+$DF'8L7#2["YHJ
+MK^U8LV35F^1555553#H`W*5([Q3'4XE1?!U7DR'4AH@8@Q3JQ@BFQIY`Q@?,
+M&;VM+!@P2U._[-7.O'/*4I2E*/H$80A!T7J?>*[6#%T\7#KZ#!K^.^X>.8$F
+M9`$0"[FP`E-"?8%01;0\,\!%X.*'$_@?=1_=_Q</#"B#,P;\P2Z8TDF!$DG-
+M$VQR>Q9/1^:93>O4_:JJKF7M$]/L:6FIM=:_7BY^;!:#JPLGZF14H63=E5)W
+M)V*\=2G"0HA9.J<G`5+9"<OXCI;H@6B!>Y(7)%%5553&]DY('GG_B[DBG"A(
+%<E>_'X``
+`
+end
index c1e8de45187f86a2475337e8622e98e6d53693f3..0a61efded76e538ea25f7acbdf9db856ae2390da 100644 (file)
@@ -103,9 +103,9 @@ DEFINE_TEST(test_read_format_isozisofs_bz2)
                        assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
                        assertEqualInt(1, archive_entry_uid(ae));
                        assertEqualInt(2, archive_entry_gid(ae));
-               } else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
+               } else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
                        /* A regular file. */
-                       assertEqualString("file", archive_entry_pathname(ae));
+                       assertEqualString("hardlink", archive_entry_pathname(ae));
                        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
                        assertEqualInt(12345684, archive_entry_size(ae));
                        assertEqualInt(0,
@@ -113,23 +113,23 @@ DEFINE_TEST(test_read_format_isozisofs_bz2)
                        assertEqualInt(0, offset);
                        assertEqualMem(p, "hello\n", 6);
                        assertEqualInt(86401, archive_entry_mtime(ae));
-                       assertEqualInt(86401, archive_entry_atime(ae));
                        assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
                        assertEqualInt(1, archive_entry_uid(ae));
                        assertEqualInt(2, archive_entry_gid(ae));
-               } else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
+               } else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
                        /* A hardlink to the regular file. */
                        /* Note: If "hardlink" gets returned before "file",
                         * then "hardlink" will get returned as a regular file
                         * and "file" will get returned as the hardlink.
                         * This test should tolerate that, since it's a
                         * perfectly permissible thing for libarchive to do. */
-                       assertEqualString("hardlink", archive_entry_pathname(ae));
+                       assertEqualString("file", archive_entry_pathname(ae));
                        assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
-                       assertEqualString("file", archive_entry_hardlink(ae));
+                       assertEqualString("hardlink", archive_entry_hardlink(ae));
                        assertEqualInt(0, archive_entry_size_is_set(ae));
                        assertEqualInt(0, archive_entry_size(ae));
                        assertEqualInt(86401, archive_entry_mtime(ae));
+                       assertEqualInt(86401, archive_entry_atime(ae));
                        assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
                        assertEqualInt(1, archive_entry_uid(ae));
                        assertEqualInt(2, archive_entry_gid(ae));