From 0bd9deb4606c99693db6b01e42233781ce2693cd Mon Sep 17 00:00:00 2001 From: Michihiro NAKAJIMA Date: Thu, 15 Oct 2009 07:37:18 -0400 Subject: [PATCH] Improve handling of Rockridge extensions' rr_moved directory and 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 --- Makefile.am | 2 + .../archive_read_support_format_iso9660.c | 205 ++++++++++++- libarchive/test/CMakeLists.txt | 1 + libarchive/test/Makefile | 1 + .../test/test_read_format_isojoliet_bz2.c | 9 +- .../test/test_read_format_isojoliet_long.c | 16 +- .../test/test_read_format_isojoliet_rr.c | 9 +- libarchive/test/test_read_format_isorr_bz2.c | 10 +- .../test/test_read_format_isorr_new_bz2.c | 10 +- .../test/test_read_format_isorr_rr_moved.c | 276 ++++++++++++++++++ ...test_read_format_isorr_rr_moved.iso.bz2.uu | 34 +++ .../test/test_read_format_isozisofs_bz2.c | 12 +- 12 files changed, 537 insertions(+), 48 deletions(-) create mode 100644 libarchive/test/test_read_format_isorr_rr_moved.c create mode 100644 libarchive/test/test_read_format_isorr_rr_moved.iso.bz2.uu diff --git a/Makefile.am b/Makefile.am index 2fcf62aa1..b14cf4585 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c index 0a19d560e..9809ec34e 100644 --- a/libarchive/archive_read_support_format_iso9660.c +++ b/libarchive/archive_read_support_format_iso9660.c @@ -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 diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index 66b98bd37..7619150bc 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -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 diff --git a/libarchive/test/Makefile b/libarchive/test/Makefile index 4f70859b8..2ef1e1b34 100644 --- a/libarchive/test/Makefile +++ b/libarchive/test/Makefile @@ -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 \ diff --git a/libarchive/test/test_read_format_isojoliet_bz2.c b/libarchive/test/test_read_format_isojoliet_bz2.c index 996ecbeb5..5e89874f3 100644 --- a/libarchive/test/test_read_format_isojoliet_bz2.c +++ b/libarchive/test/test_read_format_isojoliet_bz2.c @@ -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. */ diff --git a/libarchive/test/test_read_format_isojoliet_long.c b/libarchive/test/test_read_format_isojoliet_long.c index 3df774cba..81c1b5f22 100644 --- a/libarchive/test/test_read_format_isojoliet_long.c +++ b/libarchive/test/test_read_format_isojoliet_long.c @@ -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. */ diff --git a/libarchive/test/test_read_format_isojoliet_rr.c b/libarchive/test/test_read_format_isojoliet_rr.c index 3a5604729..e3ab2e3ea 100644 --- a/libarchive/test/test_read_format_isojoliet_rr.c +++ b/libarchive/test/test_read_format_isojoliet_rr.c @@ -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)); diff --git a/libarchive/test/test_read_format_isorr_bz2.c b/libarchive/test/test_read_format_isorr_bz2.c index 7a3cd0a1c..549c95006 100644 --- a/libarchive/test/test_read_format_isorr_bz2.c +++ b/libarchive/test/test_read_format_isorr_bz2.c @@ -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)); diff --git a/libarchive/test/test_read_format_isorr_new_bz2.c b/libarchive/test/test_read_format_isorr_new_bz2.c index 18170e4ec..bc460cda6 100644 --- a/libarchive/test/test_read_format_isorr_new_bz2.c +++ b/libarchive/test/test_read_format_isorr_new_bz2.c @@ -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 index 000000000..d17b87f54 --- /dev/null +++ b/libarchive/test/test_read_format_isorr_rr_moved.c @@ -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 index 000000000..039f2fe13 --- /dev/null +++ b/libarchive/test/test_read_format_isorr_rr_moved.iso.bz2.uu @@ -0,0 +1,34 @@ +begin 644 test_read_format_isorr_rr_moved.iso.bz2 +M0EIH.3%!62936>2O?C\``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>-USXB)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:9.UO;,F?RJUU@0[9]>/G=H[IJ]I +M[EA/3%B/W" +MI'46,VE:Q&3^U'ABINDR4R4WZ=-.$G,;:86(2!B7?*[6#%T\7#KZ#!K^.^X>.8$F +M9`$0"[FP`E-"?8%01;0\,\!%X.*'$_@?=1_=_QQ9/1^:93>O4_:JJKF7M$]/L:6FIM=:_7BY^;!:#JPLGZF14H63=E5)W +M)V*\=2G"0HA9.JY(7)%%5553&]DY('GG_B[DBG"A( +%_'X`` +` +end diff --git a/libarchive/test/test_read_format_isozisofs_bz2.c b/libarchive/test/test_read_format_isozisofs_bz2.c index c1e8de451..0a61efded 100644 --- a/libarchive/test/test_read_format_isozisofs_bz2.c +++ b/libarchive/test/test_read_format_isozisofs_bz2.c @@ -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)); -- 2.47.3