]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Preserve the natural order in ISO9660 archives for linked files (#1974)
authorRoland Clobus <rclobus@rclobus.nl>
Sat, 16 Sep 2023 17:53:54 +0000 (19:53 +0200)
committerMartin Matuska <martin@matuska.de>
Sun, 17 Sep 2023 09:15:50 +0000 (11:15 +0200)
When an ISO9660 archive contains hard links or sym links, the order of
the files in the output of 'bsdtar -tf filename' is not the natural
order.

With an extension to the key (while still supporting ISO files up to 2^48
bytes) the sorting order is guaranteed for ISO files that contain linked
files for up to 2^16 files in total.

Co-authored-by: Martin Matuska <martin@matuska.de>
libarchive/archive_read_support_format_iso9660.c
libarchive/test/test_read_format_isojoliet_long.c
libarchive/test/test_write_format_iso9660.c

index f5414be2a565db353df602100c89c632fd79e550..d22f9b45b6fc8bd234e808ac34c37665943ab2b9 100644 (file)
@@ -3015,6 +3015,11 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
        uint64_t file_key, parent_key;
        int hole, parent;
 
+       /* Reserve 16 bits for possible key collisions (needed for linked items) */
+       /* For ISO files with more than 65535 entries, reordering will still occur */
+       key <<= 16;
+       key += heap->used & 0xFFFF;
+
        /* Expand our pending files list as necessary. */
        if (heap->used >= heap->allocated) {
                struct file_info **new_pending_files;
index 4283c399fbb478ee51d00bcf88a05fbe6819655f..4329e656392e72acebe05ec45bf15d343e84be28 100644 (file)
@@ -115,7 +115,7 @@ DEFINE_TEST(test_read_format_isojoliet_long)
        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));
@@ -129,9 +129,9 @@ 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). */
        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));
        assertEqualInt(archive_entry_is_encrypted(ae), 0);
        assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
index e4e98bb95c29dfd728e0c08e6df8cecebc9ba9f5..bb6a24a6143153b2954fe6e9bc8fbcf26ee92400 100644 (file)
@@ -385,14 +385,14 @@ DEFINE_TEST(test_write_format_iso9660)
        assertEqualInt(2048, archive_entry_size(ae));
 
        /*
-        * Read "hardlnk"
+        * Read "file"
         */
        assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
        assertEqualInt(2, archive_entry_atime(ae));
        assertEqualInt(3, archive_entry_birthtime(ae));
        assertEqualInt(4, archive_entry_ctime(ae));
        assertEqualInt(5, archive_entry_mtime(ae));
-       assertEqualString("hardlnk", archive_entry_pathname(ae));
+       assertEqualString("file", archive_entry_pathname(ae));
        assert((AE_IFREG | 0555) == archive_entry_mode(ae));
        assertEqualInt(2, archive_entry_nlink(ae));
        assertEqualInt(8, archive_entry_size(ae));
@@ -400,15 +400,15 @@ DEFINE_TEST(test_write_format_iso9660)
        assertEqualMem(buff2, "12345678", 8);
 
        /*
-        * Read "file"
+        * Read "hardlnk"
         */
        assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
        assertEqualInt(2, archive_entry_atime(ae));
        assertEqualInt(3, archive_entry_birthtime(ae));
        assertEqualInt(4, archive_entry_ctime(ae));
        assertEqualInt(5, archive_entry_mtime(ae));
-       assertEqualString("file", archive_entry_pathname(ae));
-       assertEqualString("hardlnk", archive_entry_hardlink(ae));
+       assertEqualString("hardlnk", archive_entry_pathname(ae));
+       assertEqualString("file", archive_entry_hardlink(ae));
        assert((AE_IFREG | 0555) == archive_entry_mode(ae));
        assertEqualInt(2, archive_entry_nlink(ae));
        assertEqualInt(0, archive_entry_size(ae));
@@ -982,13 +982,13 @@ DEFINE_TEST(test_write_format_iso9660)
        assertEqualInt(2048, archive_entry_size(ae));
 
        /*
-        * Read "hardlink"
+        * Read "file"
         */
        assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
        assertEqualInt(5, archive_entry_atime(ae));
        assertEqualInt(5, archive_entry_ctime(ae));
        assertEqualInt(5, archive_entry_mtime(ae));
-       assertEqualString("HARDLNK", archive_entry_pathname(ae));
+       assertEqualString("FILE", archive_entry_pathname(ae));
        assertEqualString(NULL, archive_entry_hardlink(ae));
        assert((AE_IFREG | 0400) == archive_entry_mode(ae));
        assertEqualInt(8, archive_entry_size(ae));
@@ -996,15 +996,15 @@ DEFINE_TEST(test_write_format_iso9660)
        assertEqualMem(buff2, "12345678", 8);
 
        /*
-        * Read "file"
+        * Read "hardlnk"
         */
        assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
        assertEqualInt(5, archive_entry_atime(ae));
        assertEqualInt(0, archive_entry_birthtime(ae));
        assertEqualInt(5, archive_entry_ctime(ae));
        assertEqualInt(5, archive_entry_mtime(ae));
-       assertEqualString("FILE", archive_entry_pathname(ae));
-       assertEqualString("HARDLNK", archive_entry_hardlink(ae));
+       assertEqualString("HARDLNK", archive_entry_pathname(ae));
+       assertEqualString("FILE", archive_entry_hardlink(ae));
        assert((AE_IFREG | 0400) == archive_entry_mode(ae));
        assertEqualInt(2, archive_entry_nlink(ae));
        assertEqualInt(0, archive_entry_size(ae));