From 04725edc318a3d89f0ab709da6809a2965a6e0e4 Mon Sep 17 00:00:00 2001 From: Michihiro NAKAJIMA Date: Tue, 25 Sep 2012 07:08:20 +0900 Subject: [PATCH] Allow FreeBSD mtree's nochange keyword. --- .../archive_read_support_format_mtree.c | 28 +++++-- libarchive/test/test_read_format_mtree.c | 82 +++++++++++++++++++ 2 files changed, 102 insertions(+), 8 deletions(-) diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c index e1413a373..d3a2a14b1 100644 --- a/libarchive/archive_read_support_format_mtree.c +++ b/libarchive/archive_read_support_format_mtree.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011 #define MTREE_HAS_UNAME 0x0400 #define MTREE_HAS_OPTIONAL 0x0800 +#define MTREE_HAS_NOCHANGE 0x1000 /* FreeBSD specific */ struct mtree_option { struct mtree_option *next; @@ -369,7 +370,7 @@ bid_keyword(const char *p, ssize_t len) "md5", "md5digest", "mode", NULL }; static const char *keys_no[] = { - "nlink", "optional", NULL + "nlink", "nochange", "optional", NULL }; static const char *keys_r[] = { "rmd160", "rmd160digest", NULL @@ -1197,15 +1198,19 @@ parse_file(struct archive_read *a, struct archive_entry *entry, * if it wasn't already parsed from the specification. */ if (st != NULL) { - if ((parsed_kws & MTREE_HAS_DEVICE) == 0 && + if (((parsed_kws & MTREE_HAS_DEVICE) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) && (archive_entry_filetype(entry) == AE_IFCHR || archive_entry_filetype(entry) == AE_IFBLK)) archive_entry_set_rdev(entry, st->st_rdev); - if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0) + if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_gid(entry, st->st_gid); - if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0) + if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_uid(entry, st->st_uid); - if ((parsed_kws & MTREE_HAS_MTIME) == 0) { + if ((parsed_kws & MTREE_HAS_MTIME) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) { #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC archive_entry_set_mtime(entry, st->st_mtime, st->st_mtimespec.tv_nsec); @@ -1225,11 +1230,14 @@ parse_file(struct archive_read *a, struct archive_entry *entry, archive_entry_set_mtime(entry, st->st_mtime, 0); #endif } - if ((parsed_kws & MTREE_HAS_NLINK) == 0) + if ((parsed_kws & MTREE_HAS_NLINK) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_nlink(entry, st->st_nlink); - if ((parsed_kws & MTREE_HAS_PERM) == 0) + if ((parsed_kws & MTREE_HAS_PERM) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_perm(entry, st->st_mode); - if ((parsed_kws & MTREE_HAS_SIZE) == 0) + if ((parsed_kws & MTREE_HAS_SIZE) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_size(entry, st->st_size); archive_entry_set_ino(entry, st->st_ino); archive_entry_set_dev(entry, st->st_dev); @@ -1319,6 +1327,10 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, if (*key == '\0') return (ARCHIVE_OK); + if (strcmp(key, "nochange") == 0) { + *parsed_kws |= MTREE_HAS_NOCHANGE; + return (ARCHIVE_OK); + } if (strcmp(key, "optional") == 0) { *parsed_kws |= MTREE_HAS_OPTIONAL; return (ARCHIVE_OK); diff --git a/libarchive/test/test_read_format_mtree.c b/libarchive/test/test_read_format_mtree.c index bab4ee036..fc085920a 100644 --- a/libarchive/test/test_read_format_mtree.c +++ b/libarchive/test/test_read_format_mtree.c @@ -278,6 +278,88 @@ DEFINE_TEST(test_read_format_mtree_filenames_only) assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } +DEFINE_TEST(test_read_format_mtree_nochange) +{ + static char archive[] = + "#mtree\n" + "./a type=file mode=0644 time=123\n" + "./b type=file mode=0644 time=234\n" + "./c type=file mode=0644 time=345\n"; + static char archive2[] = + "#mtree\n" + "./a type=file mode=0644 time=123 nochange\n" + "./b type=file mode=0644 time=234\n" + "./c type=file mode=0644 time=345 nochange\n"; + struct archive_entry *ae; + struct archive *a; + + assertMakeFile("a", 0640, "12345"); + assertMakeFile("b", 0664, "123456"); + assertMakeFile("c", 0755, "1234567"); + + /* + * Test 1. Read a mtree archive without `nochange' keyword. + */ + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "./a"); + assertEqualInt(archive_entry_mode(ae), AE_IFREG | 0644); + assertEqualInt(archive_entry_mtime(ae), 123); + assertEqualInt(archive_entry_size(ae), 5); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "./b"); + assertEqualInt(archive_entry_mode(ae), AE_IFREG | 0644); + assertEqualInt(archive_entry_mtime(ae), 234); + assertEqualInt(archive_entry_size(ae), 6); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "./c"); + assertEqualInt(archive_entry_mode(ae), AE_IFREG | 0644); + assertEqualInt(archive_entry_mtime(ae), 345); + assertEqualInt(archive_entry_size(ae), 7); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualInt(3, archive_file_count(a)); + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + + /* + * Test 2. Read a mtree archive with `nochange' keyword. + */ + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive2, sizeof(archive2))); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "./a"); + assertEqualInt(archive_entry_mode(ae), AE_IFREG | 0640); + assert(archive_entry_mtime(ae) != 123); + assertEqualInt(archive_entry_size(ae), 5); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "./b"); + assertEqualInt(archive_entry_mode(ae), AE_IFREG | 0644); + assertEqualInt(archive_entry_mtime(ae), 234); + assertEqualInt(archive_entry_size(ae), 6); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "./c"); + assertEqualInt(archive_entry_mode(ae), AE_IFREG | 0755); + assert(archive_entry_mtime(ae) != 345); + assertEqualInt(archive_entry_size(ae), 7); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualInt(3, archive_file_count(a)); + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + DEFINE_TEST(test_read_format_mtree_nomagic_v1_form) { const char reffile[] = "test_read_format_mtree_nomagic.mtree"; -- 2.47.3