]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Allow FreeBSD mtree's nochange keyword.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 24 Sep 2012 22:08:20 +0000 (07:08 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 24 Sep 2012 22:08:20 +0000 (07:08 +0900)
libarchive/archive_read_support_format_mtree.c
libarchive/test/test_read_format_mtree.c

index e1413a373f2ecc4a766a1992faf088e28e2898d4..d3a2a14b138e71b9db8062821dab47dc0216d8b0 100644 (file)
@@ -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);
index bab4ee03652f730c238d34576a6ef073660fe275..fc085920ae0cddd8fb0e902cb847b6a94c69d25d 100644 (file)
@@ -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";