]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Merge pull request #2717 from peakschris/cb_windows
authorTim Kientzle <kientzle@acm.org>
Fri, 22 Aug 2025 15:13:40 +0000 (08:13 -0700)
committerMartin Matuska <martin@matuska.de>
Tue, 23 Sep 2025 20:58:57 +0000 (22:58 +0200)
bsdtar: Allow @filename to have CRLF endings
(cherry picked from commit 53135ca48ed948216c1875888c8a1e30761610a1)

Makefile.am
libarchive/archive_read_support_format_mtree.c
tar/test/CMakeLists.txt
tar/test/test_crlf_mtree.c [new file with mode: 0644]
test_utils/test_main.c

index 05ff1b7c4ca1e2b656584f966d39b9617006ca47..0226f25173e2520f724f058240194fbd32030591 100644 (file)
@@ -1145,6 +1145,7 @@ bsdtar_test_SOURCES= \
        tar/test/test_0.c \
        tar/test/test_basic.c \
        tar/test/test_copy.c \
+       tar/test/test_crlf_mtree.c \
        tar/test/test_empty_mtree.c \
        tar/test/test_extract_tar_Z.c \
        tar/test/test_extract_tar_bz2.c \
index fb0f946b038967596cfe7950390b4aae5847c187..f508a8af153d98adb21a7b5d24974469beef4486 100644 (file)
@@ -1073,6 +1073,8 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
                /* Non-printable characters are not allowed */
                for (s = p;s < p + len - 1; s++) {
                        if (!isprint((unsigned char)*s) && *s != '\t') {
+                               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                                       "Non-printable character 0x%02X", (unsigned char)(*s));
                                r = ARCHIVE_FATAL;
                                break;
                        }
@@ -2130,6 +2132,13 @@ readline(struct archive_read *a, struct mtree *mtree, char **start,
                for (u = mtree->line.s + find_off; *u; ++u) {
                        if (u[0] == '\n') {
                                /* Ends with unescaped newline. */
+                               /* Check if preceded by '\r' for CRLF handling */
+                               if (u > mtree->line.s && u[-1] == '\r') {
+                                       /* CRLF ending - remove the '\r' */
+                                       u[-1] = '\n';
+                                       u[0] = '\0';
+                                       total_size--;
+                               }
                                *start = mtree->line.s;
                                return total_size;
                        } else if (u[0] == '#') {
@@ -2144,6 +2153,11 @@ readline(struct archive_read *a, struct mtree *mtree, char **start,
                                        total_size -= 2;
                                        mtree->line.s[total_size] = '\0';
                                        break;
+                               } else if (u[1] == '\r' && u[2] == '\n') {
+                                       /* Trim escaped CRLF. */
+                                       total_size -= 3;
+                                       mtree->line.s[total_size] = '\0';
+                                       break;
                                } else if (u[1] != '\0') {
                                        /* Skip the two-char escape sequence */
                                        ++u;
index 7a3803bdcb66cefa0d99f357ef7c958b6d9a2c1f..d3c0bd22af9aabac0a664d6f2cdbbce36133a526 100644 (file)
@@ -14,6 +14,7 @@ IF(ENABLE_TAR AND ENABLE_TEST)
     test_0.c
     test_basic.c
     test_copy.c
+    test_crlf_mtree.c
     test_empty_mtree.c
     test_extract_tar_Z.c
     test_extract_tar_bz2.c
diff --git a/tar/test/test_crlf_mtree.c b/tar/test/test_crlf_mtree.c
new file mode 100644 (file)
index 0000000..5ef8811
--- /dev/null
@@ -0,0 +1,74 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2018 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Arshan Khanifar <arshankhanifar@gmail.com>
+ * under sponsorship from the FreeBSD Foundation.
+ */
+#include "test.h"
+
+DEFINE_TEST(test_crlf_mtree)
+{
+       char *p0;
+       size_t s;
+       int r;
+       p0 = NULL;
+       char *content = "#mtree\r\n"
+               "f type=file uname=\\\r\n"
+               "root gname=root mode=0755 content=bar/foo\r\n"
+               "g type=file uname=root gname=root mode=0755 content=bar/goo\r\n";
+       char *filename = "output.tar";
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       char *p;
+#endif
+
+       /* an absolute path to mtree file */
+       char *mtree_file = "/METALOG.mtree";
+       char *absolute_path = malloc(strlen(testworkdir) + strlen(mtree_file) + 1);
+       strcpy(absolute_path, testworkdir);
+       strcat(absolute_path, mtree_file );
+
+       /* Create an archive using an mtree file. */
+       assertMakeFile(absolute_path, 0777, content);
+       assertMakeDir("bar", 0775);
+       assertMakeFile("bar/foo", 0777, "abc");
+       assertMakeFile("bar/goo", 0777, "abc");
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       p = absolute_path;
+       while(*p != '\0') {
+               if (*p == '/')
+                       *p = '\\';
+               p++;
+       }
+
+       r = systemf("%s -cf %s @%s >step1.out 2>step1.err", testprog, filename, absolute_path);
+       failure("Error invoking %s -cf %s -C bar @%s", testprog, filename, absolute_path);
+#else
+       r = systemf("%s -cf %s \"@%s\" >step1.out 2>step1.err", testprog, filename, absolute_path);
+       failure("Error invoking %s -cf %s -C bar \"@%s\"", testprog, filename, absolute_path);
+#endif
+
+       assertEqualInt(r, 0);
+       assertEmptyFile("step1.out");
+       assertEmptyFile("step1.err");
+
+       /* Do validation of the constructed archive. */
+
+       p0 = slurpfile(&s, "output.tar");
+       if (!assert(p0 != NULL))
+               goto done;
+       if (!assert(s >= 2048))
+               goto done;
+       assertEqualMem(p0 + 0, "f", 2);
+       assertEqualMem(p0 + 512, "abc", 4);
+       assertEqualMem(p0 + 1024, "g", 2);
+       assertEqualMem(p0 + 1536, "abc", 4);
+done:
+       free(p0);
+       free(absolute_path);
+}
+
+
index c4244e9c6bcaa8ab4cf9641f8b3bb2c7188d6d5c..48698535526a062d1ac4a10a4c8c3a12f2e8bb15 100644 (file)
@@ -4094,6 +4094,9 @@ main(int argc, char **argv)
        if (testprogfile == NULL)
        {
                tmp2_len = strlen(testprogdir) + 1 + strlen(PROGRAM) + 1;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+               tmp2_len += 4;
+#endif
                if ((tmp2 = malloc(tmp2_len)) == NULL)
                {
                        fprintf(stderr, "ERROR: Out of memory.");
@@ -4102,6 +4105,9 @@ main(int argc, char **argv)
                strncpy(tmp2, testprogdir, tmp2_len);
                strncat(tmp2, "/", tmp2_len);
                strncat(tmp2, PROGRAM, tmp2_len);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+               strncat(tmp2, ".exe", tmp2_len);
+#endif
                testprogfile = tmp2;
        }