From: Tim Kientzle Date: Fri, 22 Aug 2025 15:13:40 +0000 (-0700) Subject: Merge pull request #2717 from peakschris/cb_windows X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=af9e8bf368852de36d37895b25b908cd6c625226;p=thirdparty%2Flibarchive.git Merge pull request #2717 from peakschris/cb_windows bsdtar: Allow @filename to have CRLF endings (cherry picked from commit 53135ca48ed948216c1875888c8a1e30761610a1) --- diff --git a/Makefile.am b/Makefile.am index 05ff1b7c4..0226f2517 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c index fb0f946b0..f508a8af1 100644 --- a/libarchive/archive_read_support_format_mtree.c +++ b/libarchive/archive_read_support_format_mtree.c @@ -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; diff --git a/tar/test/CMakeLists.txt b/tar/test/CMakeLists.txt index 7a3803bdc..d3c0bd22a 100644 --- a/tar/test/CMakeLists.txt +++ b/tar/test/CMakeLists.txt @@ -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 index 000000000..5ef881136 --- /dev/null +++ b/tar/test/test_crlf_mtree.c @@ -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 + * 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); +} + + diff --git a/test_utils/test_main.c b/test_utils/test_main.c index c4244e9c6..486985355 100644 --- a/test_utils/test_main.c +++ b/test_utils/test_main.c @@ -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; }