From ae12af2ea4fc586d814c13faacf97f246fff6350 Mon Sep 17 00:00:00 2001 From: Ivan Trubach Date: Wed, 24 Jul 2024 21:34:38 +0300 Subject: [PATCH] xar: 1.6.1 -> 498 This change switches the xar package from unmaintained fork of the original project to the Apple Open Source tarball. See also https://repology.org/project/xar/versions Since the package is essentially rewritten from scratch, we take an opportunity and move it to pkgs/by-name/xa/xar (formatted with nixfmt). We also remove Windows from the supported platforms because even before this change pkgsCross.mingwW64.xar failed with xar> configure: error: can not detect the size of your system's uid_t type --- pkgs/by-name/xa/xar/package.nix | 177 ++++ ...e-tests-for-Python-3-and-Nix-sandbox.patch | 961 ++++++++++++++++++ ...-Update-for-modern-liblzma5-versions.patch | 153 +++ ...defined-EXT2_ECOMPR_FL-for-e2fsprogs.patch | 39 + ...4-Fix-compatibility-with-openssl-1.0.patch | 60 ++ ...5-Fix-configure.ac-for-Linux-headers.patch | 123 +++ .../0006-Fix-more-non-Darwin-stuff.patch | 38 + ...lized-constant-with-define-statement.patch | 33 + ...ac-not-finding-AR-with-target-prefix.patch | 37 + ...d-useless-descriptions-to-AC_DEFINE.patch} | 42 +- ...ac-for-openssl-libxml2-liblzma-and-.patch} | 96 +- ...udes-and-silence-string-format-warni.patch | 104 ++ ...-char-signedness-for-ARM-and-PowerPC.patch | 46 + ...Enable-extended-attributes-for-btrfs.patch | 43 + ...-segfault-when-copying-xattr-buffers.patch | 123 +++ ...x-segfault-in-xar_attrcopy_from_heap.patch | 59 ++ ...16-Do-not-set-property-for-empty-ACL.patch | 90 ++ .../0017-Fix-time-format-for-musl.patch | 75 ++ ...Replace-memcpy-with-memmove-for-musl.patch | 25 + pkgs/tools/compression/xar/default.nix | 49 - pkgs/top-level/all-packages.nix | 2 - 21 files changed, 2283 insertions(+), 92 deletions(-) create mode 100644 pkgs/by-name/xa/xar/package.nix create mode 100644 pkgs/by-name/xa/xar/patches/0001-Update-tests-for-Python-3-and-Nix-sandbox.patch create mode 100644 pkgs/by-name/xa/xar/patches/0002-Update-for-modern-liblzma5-versions.patch create mode 100644 pkgs/by-name/xa/xar/patches/0003-Fix-undefined-EXT2_ECOMPR_FL-for-e2fsprogs.patch create mode 100644 pkgs/by-name/xa/xar/patches/0004-Fix-compatibility-with-openssl-1.0.patch create mode 100644 pkgs/by-name/xa/xar/patches/0005-Fix-configure.ac-for-Linux-headers.patch create mode 100644 pkgs/by-name/xa/xar/patches/0006-Fix-more-non-Darwin-stuff.patch create mode 100644 pkgs/by-name/xa/xar/patches/0007-replace-initialized-constant-with-define-statement.patch create mode 100644 pkgs/by-name/xa/xar/patches/0008-Fix-configure.ac-not-finding-AR-with-target-prefix.patch rename pkgs/{tools/compression/xar/0001-Add-useless-descriptions-to-AC_DEFINE.patch => by-name/xa/xar/patches/0009-Add-useless-descriptions-to-AC_DEFINE.patch} (70%) rename pkgs/{tools/compression/xar/0002-Use-pkg-config-for-libxml2.patch => by-name/xa/xar/patches/0010-Update-configure.ac-for-openssl-libxml2-liblzma-and-.patch} (51%) create mode 100644 pkgs/by-name/xa/xar/patches/0011-Fix-missing-includes-and-silence-string-format-warni.patch create mode 100644 pkgs/by-name/xa/xar/patches/0012-Fix-char-signedness-for-ARM-and-PowerPC.patch create mode 100644 pkgs/by-name/xa/xar/patches/0013-Enable-extended-attributes-for-btrfs.patch create mode 100644 pkgs/by-name/xa/xar/patches/0014-Fix-segfault-when-copying-xattr-buffers.patch create mode 100644 pkgs/by-name/xa/xar/patches/0015-Fix-segfault-in-xar_attrcopy_from_heap.patch create mode 100644 pkgs/by-name/xa/xar/patches/0016-Do-not-set-property-for-empty-ACL.patch create mode 100644 pkgs/by-name/xa/xar/patches/0017-Fix-time-format-for-musl.patch create mode 100644 pkgs/by-name/xa/xar/patches/0018-Replace-memcpy-with-memmove-for-musl.patch delete mode 100644 pkgs/tools/compression/xar/default.nix diff --git a/pkgs/by-name/xa/xar/package.nix b/pkgs/by-name/xa/xar/package.nix new file mode 100644 index 000000000000000..888e1b18f909259 --- /dev/null +++ b/pkgs/by-name/xa/xar/package.nix @@ -0,0 +1,177 @@ +{ + lib, + stdenv, + fetchFromGitHub, + applyPatches, + autoreconfHook, + pkg-config, + nix-update-script, + + # Required dependencies. + zlib, + libxml2, + + # Optional dependencies. + e2fsprogs, + bzip2, + xz, # lzma + + # Platform-specific dependencies. + acl, + musl-fts, + openssl, + darwin, # CommonCrypto + + # for tests + testers, + python3, + libxslt, # xsltproc + runCommand, + runCommandCC, + makeWrapper, + xar, +}: +stdenv.mkDerivation (finalAttrs: { + pname = "xar"; + version = "498"; + + src = fetchFromGitHub { + owner = "apple-oss-distributions"; + repo = "xar"; + rev = "xar-${finalAttrs.version}"; + hash = "sha256-RyWeR/ZnDBHIZhwzVxETdrTTPQA2VgsLZegRkxX1240="; + }; + + patches = lib.filesystem.listFilesRecursive ./patches; + + # We do not use or modify files outside of the xar subdirectory. + patchFlags = [ "-p2" ]; + sourceRoot = "source/xar"; + + outputs = [ + "out" + "lib" + "dev" + ]; + + strictDeps = true; + + nativeBuildInputs = [ + autoreconfHook + pkg-config + ]; + + # For some reason libxml2 package headers are in subdirectory and thus aren’t + # picked up by stdenv’s C compiler wrapper (see ccWrapper_addCVars). This + # doesn’t really belong here and either should be part of libxml2 package or + # libxml2 in Nixpkgs can just fix their header paths. + env.NIX_CFLAGS_COMPILE = "-isystem ${libxml2.dev}/include/libxml2"; + + buildInputs = + [ + zlib + libxml2 + bzip2 + xz + e2fsprogs + ] + # Darwin uses CommonCrypto, other platforms use openssl. + ++ lib.optional stdenv.hostPlatform.isDarwin darwin.CommonCrypto + ++ lib.optional (!stdenv.hostPlatform.isDarwin) openssl + ++ lib.optional stdenv.hostPlatform.isLinux acl + ++ lib.optional stdenv.hostPlatform.isMusl musl-fts; + + passthru = + let + patchedSource = applyPatches { inherit (finalAttrs) src patches; }; + pythonForTests = python3.withPackages (p: [ p.xattr ]); + in + { + # Tests xar outside of the Nix sandbox (extended attributes are not supported + # in Nix sandbox, e.g. filtered with seccomp on Linux). + # + # Run with + # $ nix run --file . xar.impureTests.integrationTest + # Ensure that all tests are PASSED and none are FAILED or SKIPPED. + impureTests.integrationTest = + runCommand "xar-impure-tests-integration-test" + { + src = patchedSource; + xar = finalAttrs.finalPackage; + xsltproc = lib.getBin libxslt; + pythonInterpreter = pythonForTests.interpreter; + nativeBuildInputs = [ makeWrapper ]; + } + '' + makeWrapper "$pythonInterpreter" "$out/bin/$name" \ + --prefix PATH : "$xar/bin" \ + --suffix PATH : "$xsltproc/bin" \ + --add-flags -- \ + --add-flags "$src/xar/test/run-all.py" + ''; + + tests = lib.optionalAttrs (stdenv.buildPlatform.canExecute stdenv.hostPlatform) { + version = testers.testVersion { + package = finalAttrs.finalPackage; + version = "1.8dev"; + }; + + integrationTest = + runCommand "xar-tests-integration-test" + { + src = patchedSource; + strictDeps = true; + pythonExecutable = pythonForTests.executable; + nativeBuildInputs = [ + finalAttrs.finalPackage + pythonForTests + libxslt + ]; + } + '' + "$pythonExecutable" "$src"/xar/test/run-all.py + touch "$out" + ''; + + smokeTest = + runCommandCC "xar-tests-smoke-test" + { + src = patchedSource; + strictDeps = true; + nativeBuildInputs = [ finalAttrs.finalPackage ]; + buildInputs = [ + finalAttrs.finalPackage + openssl + ]; + } + '' + cp "$src"/xar/test/{buffer.c,validate.c} . + "$CC" -lxar -o buffer buffer.c + "$CC" -lxar -lcrypto -o validate validate.c + ./buffer validate.c + xar -x -f test.xar + diff validate.c mydir/secondfile + ./validate test.xar + touch "$out" + ''; + }; + + updateScript = nix-update-script { + extraArgs = [ + "--version-regex" + "xar-(.*)" + ]; + }; + }; + + meta = { + homepage = "https://github.com/apple-oss-distributions/xar"; + description = "An easily extensible archive format"; + license = lib.licenses.bsd3; + maintainers = + lib.teams.darwin.members + ++ lib.attrValues { inherit (lib.maintainers) copumpkin tie; }; + platforms = lib.platforms.unix; + mainProgram = "xar"; + }; +}) diff --git a/pkgs/by-name/xa/xar/patches/0001-Update-tests-for-Python-3-and-Nix-sandbox.patch b/pkgs/by-name/xa/xar/patches/0001-Update-tests-for-Python-3-and-Nix-sandbox.patch new file mode 100644 index 000000000000000..36ca0650f7b899a --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0001-Update-tests-for-Python-3-and-Nix-sandbox.patch @@ -0,0 +1,961 @@ +From 79d0d4aeba6869c6652f6a9d6d69e272e8a4fd4c Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 12:53:54 +0300 +Subject: [PATCH 01/18] Update tests for Python 3 and Nix sandbox + +This change updates integration tests for Python 3 and fixes some +assumptions to work under Nix sandbox (in particular, extended +attributes are not allowed). + +Also updates xar/test/validate.c for modern OpenSSL versions. +--- + xar/test/attr.py | 54 +++++++++++++++++++------- + xar/test/buffer.c | 3 +- + xar/test/checksums.py | 75 +++++++++++++++++++----------------- + xar/test/compression.py | 27 ++++++++----- + xar/test/data.py | 19 +++++---- + xar/test/hardlink.py | 12 ++++-- + xar/test/heap.py | 27 +++++++------ + xar/test/integrity.py | 45 ++++++++++++---------- + xar/test/run-all.py | 25 ++++++++++++ + xar/test/util.py | 85 ++++++++++++++++++++++++++++++++++++----- + xar/test/validate.c | 32 +++++++++------- + 11 files changed, 282 insertions(+), 122 deletions(-) + create mode 100755 xar/test/run-all.py + +diff --git a/xar/test/attr.py b/xar/test/attr.py +index adc2c56..c28a4e6 100755 +--- a/xar/test/attr.py ++++ b/xar/test/attr.py +@@ -6,6 +6,7 @@ import os + import os.path + import shutil + import subprocess ++import sys + import xattr + + import util +@@ -26,20 +27,27 @@ import util + class MissingExtendedAttributeError(AssertionError): + pass + +-def _random_big_data(bytes=65536, path="/dev/random"): ++def _random_big_data(bytes=65536): + """ + Returns a random string with the number of bytes requested. Due to xar + implementation details, this should be greater than 4096 (32768 for + compressed heap testing). + + """ +- with open(path, "r") as f: +- return f.read(bytes) ++ return os.urandom(bytes) ++ ++def _to_bytes(s): ++ if isinstance(s, str): ++ return s.encode("utf-8") ++ return s + + def _test_xattr_on_file_with_contents(filename, file_contents, xattrs=[], xar_create_flags=[], xar_extract_flags=[]): ++ file_contents = _to_bytes(file_contents) ++ xattr_prefix = "user." if sys.platform != "darwin" else "" ++ xattrs = [(xattr_prefix + k, _to_bytes(v)) for k, v in xattrs] + try: + # Write file out +- with open(filename, "w") as f: ++ with open(filename, "wb") as f: + f.write(file_contents) + for (key, value) in xattrs: + xattr.setxattr(f, key, value) +@@ -51,14 +59,16 @@ def _test_xattr_on_file_with_contents(filename, file_contents, xattrs=[], xar_cr + with util.directory_created("extracted") as directory: + # Validate resulting xattrs + subprocess.check_call(["xar", "-x", "-C", directory, "-f", path] + xar_extract_flags) ++ extracted_filename = os.path.join(directory, filename) ++ expected_set = {key for key, _ in xattrs} ++ actual_set = set(xattr.listxattr(os.path.join(directory, filename))) ++ for key in expected_set - actual_set: ++ raise MissingExtendedAttributeError("extended attribute \"{n}\" missing after extraction".format(n=key)) + for (key, value) in xattrs: +- try: +- assert xattr.getxattr(os.path.join(directory, filename), key) == value, "extended attribute \"{n}\" has incorrect contents after extraction".format(n=key) +- except KeyError: +- raise MissingExtendedAttributeError("extended attribute \"{n}\" missing after extraction".format(n=key)) ++ assert xattr.getxattr(extracted_filename, key) == value, "extended attribute \"{n}\" has incorrect contents after extraction".format(n=key) + + # Validate file contents +- with open(os.path.join(directory, filename), "r") as f: ++ with open(os.path.join(directory, filename), "rb") as f: + if f.read() != file_contents: + raise MissingExtendedAttributeError("archived file \"{f}\" has has incorrect contents after extraction".format(f=filename)) + finally: +@@ -73,36 +83,47 @@ def _test_xattr_on_file_with_contents(filename, file_contents, xattrs=[], xar_cr + # tests are commented out awaiting a day when this might be different. + + # def empty_xattr_empty_file(filename): ++# util.skip_if_no_xattrs_support() + # _test_xattr_on_file_with_contents(filename, "", xattrs=[("foo", "")]) + + def small_xattr_empty_file(filename): ++ util.skip_if_no_xattrs_support() + _test_xattr_on_file_with_contents(filename, "", xattrs=[("foo", "1234")]) + + def large_xattr_empty_file(filename): ++ util.skip_if_no_xattrs_support() + _test_xattr_on_file_with_contents(filename, "", xattrs=[("foo", _random_big_data(5000))]) + + # def empty_xattr_small_file(filename): ++# util.skip_if_no_xattrs_support() + # _test_xattr_on_file_with_contents(filename, "small.file.contents", xattrs=[("foo", "")]) + + def small_xattr_small_file(filename): ++ util.skip_if_no_xattrs_support() + _test_xattr_on_file_with_contents(filename, "small.file.contents", xattrs=[("foo", "1234")]) + + def large_xattr_small_file(filename): ++ util.skip_if_no_xattrs_support() + _test_xattr_on_file_with_contents(filename, "small.file.contents", xattrs=[("foo", _random_big_data(4567))]) + + # def empty_xattr_large_file(filename): ++# util.skip_if_no_xattrs_support() + # _test_xattr_on_file_with_contents(filename, _random_big_data(10000000), xattrs=[("foo", "")]) + + def small_xattr_large_file(filename): ++ util.skip_if_no_xattrs_support() + _test_xattr_on_file_with_contents(filename, _random_big_data(5000000), xattrs=[("foo", "1234")]) + + def large_xattr_large_file(filename): ++ util.skip_if_no_xattrs_support() + _test_xattr_on_file_with_contents(filename, _random_big_data(9876543), xattrs=[("foo", _random_big_data(6543))]) + + def multiple_xattrs(filename): ++ util.skip_if_no_xattrs_support() + _test_xattr_on_file_with_contents(filename, "", xattrs=[("foo", "bar"), ("baz", "1234"), ("quux", "more")]) # ("empty", "") + + def distribution_create(filename): ++ util.skip_if_no_xattrs_support() + try: + _test_xattr_on_file_with_contents(filename, "dummy", xattrs=[("foo", "bar")], xar_create_flags=["--distribution"]) + except MissingExtendedAttributeError: +@@ -114,6 +135,7 @@ def distribution_create(filename): + # when it can. + + # def distribution_extract(filename): ++# util.skip_if_no_xattrs_support() + # try: + # _test_xattr_on_file_with_contents(filename, "dummy", xattrs=[("foo", "bar")], xar_extract_flags=["--distribution"]) + # except MissingExtendedAttributeError: +@@ -128,12 +150,18 @@ TEST_CASES = (small_xattr_empty_file, large_xattr_empty_file, + multiple_xattrs, distribution_create) + + if __name__ == "__main__": ++ failed = False + for case in TEST_CASES: ++ func_name = case.__name__ + try: +- case(case.func_name) +- print("PASSED: {f}".format(f=case.func_name)) ++ case(func_name) ++ print("PASSED: {f}".format(f=func_name)) + except (AssertionError, IOError, subprocess.CalledProcessError): +- import sys, os +- print("FAILED: {f}".format(f=case.func_name)) ++ failed = True ++ print("FAILED: {f}".format(f=func_name)) + sys.excepthook(*sys.exc_info()) + print("") ++ except util.TestCaseSkipError as e: ++ print("SKIPPED: {f}: {m}".format(f=func_name, m=e)) ++ if failed: ++ sys.exit(1) +diff --git a/xar/test/buffer.c b/xar/test/buffer.c +index a353cef..e4c5639 100644 +--- a/xar/test/buffer.c ++++ b/xar/test/buffer.c +@@ -1,5 +1,6 @@ + #include + #include ++#include + #include + #include + #include +@@ -50,7 +51,7 @@ int main(int argc, char *argv[]) + if( red < sb.st_size ) + fprintf(stderr, "Incomplete read\n"); + +- x = xar_open("/tmp/test.xar", WRITE); ++ x = xar_open("test.xar", WRITE); + if( x == NULL ) { + fprintf(stderr, "Error creating xarchive\n"); + exit(6); +diff --git a/xar/test/checksums.py b/xar/test/checksums.py +index 7080d7c..0f39e63 100755 +--- a/xar/test/checksums.py ++++ b/xar/test/checksums.py +@@ -2,6 +2,7 @@ + + from __future__ import print_function + ++import contextlib + import hashlib + import os + import os.path +@@ -9,6 +10,7 @@ import re + import shutil + import struct + import subprocess ++import sys + + import util + +@@ -17,15 +19,21 @@ import util + # Utility Functions + # + ++@contextlib.contextmanager ++def _test_archive_created(filename, directory, *args, **kwargs): ++ with util.test_directory_created(directory) as test_directory: ++ with util.archive_created(filename, test_directory, *args, **kwargs) as path: ++ yield path ++ + def _get_numeric_value_from_header(archive_name, key): + """ + Dumps the header of the specified xar archive and extracts the header + size from the output, in bytes. + + """ +- header = subprocess.check_output(["xar", "--dump-header", "-f", archive_name]) ++ header = subprocess.check_output(["xar", "--dump-header", "-f", archive_name], text=True) + for line in header.splitlines(): +- matchdata = re.match("^(.+):\s+(.+)$", line) # magic: 0x78617221 (OK) ++ matchdata = re.match(r"^(.+):\s+(.+)$", line) # magic: 0x78617221 (OK) + assert matchdata, "unexpected output from `xar --dump-header`:\n{h}".format(h=header) + if matchdata.groups()[0] == key: + return int(matchdata.groups()[1]) +@@ -38,17 +46,14 @@ def _get_toc_size(archive_name): + return _get_numeric_value_from_header(archive_name, "Compressed TOC length") + + def _clobber_bytes_at(clobber_range, path): +- with open(path, "r+") as f: ++ with open(path, "rb+") as f: + f.seek(clobber_range[0]) +- with open("/dev/random", "r") as r: +- random_bytes = r.read(len(clobber_range)) +- f.write(random_bytes) ++ f.write(os.urandom(len(clobber_range))) + + def _verify_extraction_failed(filename): + with util.directory_created("extracted") as directory: + try: +- with open("/dev/null", "w") as n: +- returncode = subprocess.call(["xar", "-x", "-C", directory, "-f", filename], stdout=n, stderr=n) ++ returncode = subprocess.call(["xar", "-x", "-C", directory, "-f", filename], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + assert returncode != 0, "xar reported success extracting an archive with a broken TOC" + finally: + if os.path.exists(directory): +@@ -63,7 +68,7 @@ def _verify_header_checksum(filename, algorithm): + header_size = _get_header_size(filename) + toc_length = _get_toc_size(filename) + +- with open(filename, "r") as f: ++ with open(filename, "rb") as f: + f.seek(header_size) + h = hashlib.new(algorithm, f.read(toc_length)) + computed_digest = h.digest() +@@ -76,23 +81,23 @@ def _verify_header_checksum(filename, algorithm): + # + + def default_toc_checksum_validity(filename): +- with util.archive_created(filename, "/bin") as path: ++ with _test_archive_created(filename, "testdir") as path: + _verify_header_checksum(path, "sha1") + + def sha1_toc_checksum_validity(filename): +- with util.archive_created(filename, "/bin", "--toc-cksum", "sha1") as path: ++ with _test_archive_created(filename, "testdir", "--toc-cksum", "sha1") as path: + _verify_header_checksum(path, "sha1") + + def sha256_toc_checksum_validity(filename): +- with util.archive_created(filename, "/bin", "--toc-cksum", "sha256") as path: ++ with _test_archive_created(filename, "testdir", "--toc-cksum", "sha256") as path: + _verify_header_checksum(path, "sha256") + + def sha512_toc_checksum_validity(filename): +- with util.archive_created(filename, "/bin", "--toc-cksum", "sha512") as path: ++ with _test_archive_created(filename, "testdir", "--toc-cksum", "sha512") as path: + _verify_header_checksum(path, "sha512") + + def broken_toc_default_checksum(filename): +- with util.archive_created(filename, "/bin") as path: ++ with _test_archive_created(filename, "testdir") as path: + # Mess up the archive + toc_start = _get_header_size(path) + _clobber_bytes_at(range(toc_start + 4, toc_start + 4 + 100), path) # Why did the original test specify 4? No idea. +@@ -101,7 +106,7 @@ def broken_toc_default_checksum(filename): + _verify_extraction_failed(filename) + + def broken_toc_sha1_checksum(filename): +- with util.archive_created(filename, "/bin", "--toc-cksum", "sha1") as path: ++ with _test_archive_created(filename, "testdir", "--toc-cksum", "sha1") as path: + # Mess up the archive + toc_start = _get_header_size(path) + _clobber_bytes_at(range(toc_start + 4, toc_start + 4 + 100), path) # Why did the original test specify 4? No idea. +@@ -110,7 +115,7 @@ def broken_toc_sha1_checksum(filename): + _verify_extraction_failed(filename) + + def broken_toc_sha256_checksum(filename): +- with util.archive_created(filename, "/bin", "--toc-cksum", "sha256") as path: ++ with _test_archive_created(filename, "testdir", "--toc-cksum", "sha256") as path: + # Mess up the archive + toc_start = _get_header_size(path) + _clobber_bytes_at(range(toc_start + 4, toc_start + 4 + 100), path) # Why did the original test specify 4? No idea. +@@ -119,7 +124,7 @@ def broken_toc_sha256_checksum(filename): + _verify_extraction_failed(filename) + + def broken_toc_sha512_checksum(filename): +- with util.archive_created(filename, "/bin", "--toc-cksum", "sha512") as path: ++ with _test_archive_created(filename, "testdir", "--toc-cksum", "sha512") as path: + # Mess up the archive + toc_start = _get_header_size(path) + _clobber_bytes_at(range(toc_start + 4, toc_start + 4 + 100), path) # Why did the original test specify 4? No idea. +@@ -128,7 +133,7 @@ def broken_toc_sha512_checksum(filename): + _verify_extraction_failed(filename) + + def broken_heap_default_checksum(filename): +- with util.archive_created(filename, "/bin") as path: ++ with _test_archive_created(filename, "testdir") as path: + # Mess up the archive + toc_start = _get_header_size(path) + toc_size = _get_toc_size(path) +@@ -139,11 +144,11 @@ def broken_heap_default_checksum(filename): + _verify_extraction_failed(filename) + + def default_checksum_algorithm(filename): +- with util.archive_created(filename, "/bin") as path: +- header = subprocess.check_output(["xar", "--dump-header", "-f", path]) ++ with _test_archive_created(filename, "testdir") as path: ++ header = subprocess.check_output(["xar", "--dump-header", "-f", path], text=True) + found = False + for line in header.splitlines(): +- matchdata = re.match("^Checksum algorithm:\s+(\d+)\s+\\((\w+)\\)$", line) ++ matchdata = re.match(r"^Checksum algorithm:\s+(\d+)\s+\((\w+)\)$", line) + if not matchdata: + continue + found = True +@@ -156,7 +161,7 @@ def default_checksum_algorithm(filename): + # + # def invalid_checksum_algorithm(filename): + # try: +-# with util.archive_created(filename, "/bin", "--toc-cksum", "invalid-algorithm") as path: ++# with _test_archive_created(filename, "testdir", "--toc-cksum", "invalid-algorithm") as path: + # raise AssertionError("xar succeeded when it should have failed") + # except subprocess.CalledProcessError: + # pass +@@ -164,17 +169,15 @@ def default_checksum_algorithm(filename): + # It does fail for md5 explicitly, however + def md5_toc_checksum_failure(filename): + try: +- with open("/dev/null", "a") as devnull: +- with util.archive_created(filename, "/bin", "--toc-cksum", "md5", stderr=devnull) as path: +- raise AssertionError("xar succeeded when it should have failed") ++ with _test_archive_created(filename, "testdir", "--toc-cksum", "md5", stderr=subprocess.DEVNULL) as path: ++ raise AssertionError("xar succeeded when it should have failed") + except subprocess.CalledProcessError: + pass + + def md5_file_checksum_failure(filename): + try: +- with open("/dev/null", "a") as devnull: +- with util.archive_created(filename, "/bin", "--file-cksum", "md5", stderr=devnull) as path: +- raise AssertionError("xar succeeded when it should have failed") ++ with _test_archive_created(filename, "testdir", "--file-cksum", "md5", stderr=subprocess.DEVNULL) as path: ++ raise AssertionError("xar succeeded when it should have failed") + except subprocess.CalledProcessError: + pass + +@@ -185,8 +188,8 @@ def _verify_checksum_algorithm(filename, algorithm): + else: + algorithm = "sha1" + +- with util.archive_created(filename, "/bin", *additional_args) as path: +- toc = subprocess.check_output(["xar", "--dump-toc=-", "-f", path]) ++ with _test_archive_created(filename, "testdir", *additional_args) as path: ++ toc = subprocess.check_output(["xar", "--dump-toc=-", "-f", path], text=True) + found = False + for line in toc.splitlines(): + if ''.format(a=algorithm) in line or ''.format(a=algorithm) in line: +@@ -214,12 +217,16 @@ TEST_CASES = (default_toc_checksum_validity, sha1_toc_checksum_validity, sha256_ + md5_toc_checksum_failure, md5_file_checksum_failure,) + + if __name__ == "__main__": ++ failed = False + for case in TEST_CASES: ++ func_name = case.__name__ + try: +- case("{f}.xar".format(f=case.func_name)) +- print("PASSED: {f}".format(f=case.func_name)) ++ case("{f}.xar".format(f=func_name)) ++ print("PASSED: {f}".format(f=func_name)) + except (AssertionError, IOError, subprocess.CalledProcessError): +- import sys, os +- print("FAILED: {f}".format(f=case.func_name)) ++ failed = True ++ print("FAILED: {f}".format(f=func_name)) + sys.excepthook(*sys.exc_info()) + print("") ++ if failed: ++ sys.exit(1) +diff --git a/xar/test/compression.py b/xar/test/compression.py +index 2b3b2ec..7ed30ca 100755 +--- a/xar/test/compression.py ++++ b/xar/test/compression.py +@@ -2,10 +2,10 @@ + + from __future__ import print_function + +-import cStringIO + import os + import os.path + import subprocess ++import sys + import tempfile + + import util +@@ -16,10 +16,15 @@ import util + # + + def _check_compression(filename, *args, **kwargs): +- with util.archive_created(filename, "/bin", *args, **kwargs) as path: ++ with ( ++ util.directory_created("temp") as temp_directory, ++ util.chdir(temp_directory), ++ util.test_directory_created("testdir") as test_directory, ++ util.archive_created(filename, "testdir", *args, **kwargs) as path, ++ ): + with util.directory_created("extracted") as directory: + subprocess.check_call(["xar", "-x", "-f", path, "-C", directory]) +- util.assert_identical_directories("/bin", os.path.join(directory, "bin")) ++ util.assert_identical_directories(test_directory, os.path.join(directory, "testdir")) + + + # +@@ -61,14 +66,18 @@ TEST_CASES = (no_compression, default_compression, + gzip_compression_short, bzip2_compression_short, lzma_compression_short) + + if __name__ == "__main__": ++ failed = False + for case in TEST_CASES: ++ func_name = case.__name__ + try: +- case("{f}.xar".format(f=case.func_name)) +- print("PASSED: {f}".format(f=case.func_name)) ++ case("{f}.xar".format(f=func_name)) ++ print("PASSED: {f}".format(f=func_name)) + except (AssertionError, IOError, subprocess.CalledProcessError): +- import sys, os +- print("FAILED: {f}".format(f=case.func_name)) ++ failed = True ++ print("FAILED: {f}".format(f=func_name)) + sys.excepthook(*sys.exc_info()) + print("") +- except util.TestCaseSkipError, e: +- print("SKIPPED: {f}: {m}".format(f=case.func_name, m=e.message)) ++ except util.TestCaseSkipError as e: ++ print("SKIPPED: {f}: {m}".format(f=func_name, m=e)) ++ if failed: ++ sys.exit(1) +diff --git a/xar/test/data.py b/xar/test/data.py +index a9793f0..f902b78 100755 +--- a/xar/test/data.py ++++ b/xar/test/data.py +@@ -6,6 +6,7 @@ import contextlib + import os + import os.path + import subprocess ++import sys + import util + + +@@ -28,7 +29,7 @@ def _process_toc(archive_path): + subprocess.check_call(["xar", "-f", archive_path, "--dump-toc=data_toc.xml"]) + try: + result = subprocess.check_output(["xsltproc", "-o", "-", os.path.realpath(os.path.join(__file__, "..", "data.xsl")), "data_toc.xml"]) +- assert result == "", "expected no data offset, but instead found:{o}".format(o=result) ++ assert result == b"", "expected no data offset, but instead found:{o}".format(o=result) + finally: + os.unlink("data_toc.xml") + +@@ -90,14 +91,18 @@ TEST_CASES = (zero_length_default_compression, zero_length_no_compression, + mixed_length_gzip_compression, mixed_length_bzip2_compression, mixed_length_lzma_compression) + + if __name__ == "__main__": ++ failed = False + for case in TEST_CASES: ++ func_name = case.__name__ + try: +- case("{f}.xar".format(f=case.func_name)) +- print("PASSED: {f}".format(f=case.func_name)) ++ case("{f}.xar".format(f=func_name)) ++ print("PASSED: {f}".format(f=func_name)) + except (AssertionError, IOError, subprocess.CalledProcessError): +- import sys, os +- print("FAILED: {f}".format(f=case.func_name)) ++ failed = True ++ print("FAILED: {f}".format(f=func_name)) + sys.excepthook(*sys.exc_info()) + print("") +- except util.TestCaseSkipError, e: +- print("SKIPPED: {f}: {m}".format(f=case.func_name, m=e.message)) ++ except util.TestCaseSkipError as e: ++ print("SKIPPED: {f}: {m}".format(f=func_name, m=e)) ++ if failed: ++ sys.exit(1) +diff --git a/xar/test/hardlink.py b/xar/test/hardlink.py +index 5145216..da409d6 100755 +--- a/xar/test/hardlink.py ++++ b/xar/test/hardlink.py +@@ -5,6 +5,7 @@ from __future__ import print_function + import os + import os.path + import subprocess ++import sys + + import util + +@@ -58,12 +59,17 @@ def hard_link_identical_files(filename): + TEST_CASES = (hard_link_in_directory, hard_link_in_cwd, hard_link_identical_files) + + if __name__ == "__main__": ++ failed = False + for case in TEST_CASES: ++ func_name = case.__name__ + try: +- case("{f}.xar".format(f=case.func_name)) +- print("PASSED: {f}".format(f=case.func_name)) ++ case("{f}.xar".format(f=func_name)) ++ print("PASSED: {f}".format(f=func_name)) + except (AssertionError, IOError, subprocess.CalledProcessError): ++ failed = True + import sys, os +- print("FAILED: {f}".format(f=case.func_name)) ++ print("FAILED: {f}".format(f=func_name)) + sys.excepthook(*sys.exc_info()) + print("") ++ if failed: ++ sys.exit(1) +diff --git a/xar/test/heap.py b/xar/test/heap.py +index f431c77..727412a 100755 +--- a/xar/test/heap.py ++++ b/xar/test/heap.py +@@ -8,6 +8,7 @@ import os.path + import re + import shutil + import subprocess ++import sys + + import util + +@@ -19,8 +20,8 @@ import util + def _file_offsets_for_archive(path, xsl_path): + subprocess.check_call(["xar", "--dump-toc=heap_toc.xml", "-f", path]) + try: +- offsets = subprocess.check_output(["xsltproc", xsl_path, "heap_toc.xml"]) +- matches = [re.match("^(.+)\s([^\s]+)$", offset) for offset in offsets.splitlines()] ++ offsets = subprocess.check_output(["xsltproc", xsl_path, "heap_toc.xml"], text=True) ++ matches = [re.match(r"^(.+)\s([^\s]+)$", offset) for offset in offsets.splitlines()] + offsets = [(match.groups()[0], int(match.groups()[1])) for match in matches] + return offsets + finally: +@@ -33,9 +34,8 @@ def _file_offsets_for_archive(path, xsl_path): + XSL_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "heap1.xsl") + + def normal_heap(filename): +- with util.directory_created("scratch") as directory: +- shutil.copy("/bin/ls", os.path.join(directory, "ls")) +- shutil.copy(os.path.join(directory, "ls"), os.path.join(directory, "foo")) ++ with util.test_directory_created("scratch") as directory: ++ shutil.copy(os.path.join(directory, "script"), os.path.join(directory, "foo")) + with util.chdir(directory): + with util.archive_created(os.path.join("..", "heap.xar"), ".") as path: + # Verify file offsets are as we expect +@@ -50,9 +50,8 @@ def normal_heap(filename): + subprocess.check_call(["xar", "-x", "-f", path, "-C", extracted]) + + def coalesce_heap(filename): +- with util.directory_created("scratch") as directory: +- shutil.copy("/bin/ls", os.path.join(directory, "ls")) +- shutil.copy(os.path.join(directory, "ls"), os.path.join(directory, "foo")) ++ with util.test_directory_created("scratch") as directory: ++ shutil.copy(os.path.join(directory, "script"), os.path.join(directory, "foo")) + with util.chdir(directory): + with util.archive_created(os.path.join("..", "heap.xar"), ".", "--coalesce-heap") as path: + # Verify file offsets are as we expect +@@ -67,12 +66,16 @@ def coalesce_heap(filename): + TEST_CASES = (normal_heap, coalesce_heap) + + if __name__ == "__main__": ++ failed = False + for case in TEST_CASES: ++ func_name = case.__name__ + try: +- case("{f}.xar".format(f=case.func_name)) +- print("PASSED: {f}".format(f=case.func_name)) ++ case("{f}.xar".format(f=func_name)) ++ print("PASSED: {f}".format(f=func_name)) + except (AssertionError, IOError, subprocess.CalledProcessError): +- import sys, os +- print("FAILED: {f}".format(f=case.func_name)) ++ failed = True ++ print("FAILED: {f}".format(f=func_name)) + sys.excepthook(*sys.exc_info()) + print("") ++ if failed: ++ sys.exit(1) +diff --git a/xar/test/integrity.py b/xar/test/integrity.py +index c47ac6a..f4d2af7 100755 +--- a/xar/test/integrity.py ++++ b/xar/test/integrity.py +@@ -5,6 +5,7 @@ from __future__ import print_function + import os + import os.path + import subprocess ++import sys + + import util + +@@ -12,9 +13,9 @@ import util + # Utility Functions + # + +-def _test_truncation(filename, path_to_be_archived, bytes_to_chop, *args): +- with util.archive_created(filename, path_to_be_archived) as path: +- with open("/dev/null", "w") as bitbucket: ++def _test_truncation(filename, bytes_to_chop, *args): ++ with util.test_directory_created("testdir") as test_directory: ++ with util.archive_created(filename, test_directory) as path: + size = os.stat(path).st_size + while size > 0: + last_size = size +@@ -23,7 +24,7 @@ def _test_truncation(filename, path_to_be_archived, bytes_to_chop, *args): + f.truncate(size) + + with util.directory_created("scratch") as directory: +- returncode = subprocess.call(["xar", "-x", "-f", path, "-C", directory], stderr=bitbucket) ++ returncode = subprocess.call(["xar", "-x", "-f", path, "-C", directory], stderr=subprocess.DEVNULL) + assert returncode != 0, "xar claimed to succeed when extracting a truncated archive" + + # +@@ -31,42 +32,42 @@ def _test_truncation(filename, path_to_be_archived, bytes_to_chop, *args): + # + + def large_uncompressed(filename): +- _test_truncation(filename, "/usr/share/man/man1", 1024 * 1024, "--compression=none") ++ _test_truncation(filename, 1024 * 1024, "--compression=none") + + def large_default_compression(filename): +- _test_truncation(filename, "/usr/share/man/man1", 1024 * 1024) ++ _test_truncation(filename, 1024 * 1024) + + def large_gzip_compressed(filename): + util.skip_if_no_compression_support("gzip") +- _test_truncation(filename, "/usr/share/man/man1", 1024 * 1024, "--compression=gzip") ++ _test_truncation(filename, 1024 * 1024, "--compression=gzip") + + def large_bzip2_compressed(filename): + util.skip_if_no_compression_support("bzip2") +- _test_truncation(filename, "/usr/share/man/man1", 1024 * 1024, "--compression=bzip2") ++ _test_truncation(filename, 1024 * 1024, "--compression=bzip2") + + def large_lzma_compressed(filename): + util.skip_if_no_compression_support("lzma") +- _test_truncation(filename, "/usr/share/man/man1", 1024 * 1024, "--compression=lzma") ++ _test_truncation(filename, 1024 * 1024, "--compression=lzma") + + # "small" variants use a non-base-2 size to try to catch issues that occur on uneven boundaries + + def small_uncompressed(filename): +- _test_truncation(filename, "/bin", 43651, "--compression=none") ++ _test_truncation(filename, 43651, "--compression=none") + + def small_default_compression(filename): +- _test_truncation(filename, "/bin", 43651) ++ _test_truncation(filename, 43651) + + def small_gzip_compressed(filename): + util.skip_if_no_compression_support("gzip") +- _test_truncation(filename, "/bin", 43651, "--compression=gzip") ++ _test_truncation(filename, 43651, "--compression=gzip") + + def small_bzip2_compressed(filename): + util.skip_if_no_compression_support("bzip2") +- _test_truncation(filename, "/bin", 43651, "--compression=bzip2") ++ _test_truncation(filename, 43651, "--compression=bzip2") + + def small_lzma_compressed(filename): + util.skip_if_no_compression_support("lzma") +- _test_truncation(filename, "/bin", 43651, "--compression=lzma") ++ _test_truncation(filename, 43651, "--compression=lzma") + + + TEST_CASES = (large_uncompressed, large_default_compression, +@@ -75,14 +76,18 @@ TEST_CASES = (large_uncompressed, large_default_compression, + small_gzip_compressed, small_bzip2_compressed, small_lzma_compressed) + + if __name__ == "__main__": ++ failed = False + for case in TEST_CASES: ++ func_name = case.__name__ + try: +- case("{f}.xar".format(f=case.func_name)) +- print("PASSED: {f}".format(f=case.func_name)) ++ case("{f}.xar".format(f=func_name)) ++ print("PASSED: {f}".format(f=func_name)) + except (AssertionError, IOError, subprocess.CalledProcessError): +- import sys, os +- print("FAILED: {f}".format(f=case.func_name)) ++ failed = True ++ print("FAILED: {f}".format(f=func_name)) + sys.excepthook(*sys.exc_info()) + print("") +- except util.TestCaseSkipError, e: +- print("SKIPPED: {f}: {m}".format(f=case.func_name, m=e.message)) ++ except util.TestCaseSkipError as e: ++ print("SKIPPED: {f}: {m}".format(f=func_name, m=e)) ++ if failed: ++ sys.exit(1) +diff --git a/xar/test/run-all.py b/xar/test/run-all.py +new file mode 100755 +index 0000000..05e3054 +--- /dev/null ++++ b/xar/test/run-all.py +@@ -0,0 +1,25 @@ ++#!/usr/bin/env python3 ++ ++import os.path ++import subprocess ++import sys ++ ++test_suites = [ ++ "attr.py", ++ "checksums.py", ++ "compression.py", ++ "data.py", ++ "hardlink.py", ++ "heap.py", ++ "integrity.py", ++] ++ ++test_path = os.path.dirname(__file__) ++ ++failed = False ++for suite in test_suites: ++ p = subprocess.run([sys.executable, "--", os.path.join(test_path, suite)]) ++ if p.returncode: ++ failed = True ++if failed: ++ sys.exit(1) +diff --git a/xar/test/util.py b/xar/test/util.py +index da79925..423dd3c 100644 +--- a/xar/test/util.py ++++ b/xar/test/util.py +@@ -1,6 +1,8 @@ + #!/usr/bin/env python + + import contextlib ++import errno ++import functools + import hashlib + import os + import os.path +@@ -13,16 +15,65 @@ import xattr + class TestCaseSkipError(Exception): + pass + ++@functools.cache ++def _check_xattrs_supported(): ++ """ ++ Returns True if the filesystem supports extended attributes. ++ """ ++ with directory_created("empty") as directory: ++ try: ++ xattr.setxattr(directory, "user.xattrcheck", b"supported") ++ return True ++ except OSError as e: ++ if e.errno != errno.ENOTSUP: ++ raise ++ return False ++ ++def skip_if_no_xattrs_support(): ++ """ ++ Raises TestCaseSkipError if the the filesystem does not support extended ++ attributes. ++ """ ++ if not _check_xattrs_supported(): ++ raise TestCaseSkipError("filesystem does not support extended attributes") ++ ++@functools.cache ++def _check_compression_supported(type): ++ """ ++ Returns True if xar has support for the given compression type compiled ++ in. This function performs a runtime check that tries to compress data ++ with the given compression type and looks for a known error string. It ++ ignores all other errors. ++ """ ++ supported = True ++ with directory_created("empty") as directory: ++ archive_path = f"{type}_compression_check.xar" ++ try: ++ return f"{type} support not compiled in." not in subprocess.run( ++ [ ++ "xar", ++ "-c", ++ "-f", ++ archive_path, ++ "--compression=" + type, ++ directory, ++ ], ++ stdout=subprocess.PIPE, ++ text=True, ++ ).stdout ++ except: ++ # Assume that this compression type is supported. ++ pass ++ finally: ++ if os.path.exists(archive_path): ++ os.unlink(archive_path) ++ return supported ++ + def skip_if_no_compression_support(type): + """ +- Raises TestCaseSkipError if the type is "lzma" and the test is running on +- darwin (OS X). In the future, we should add a hidden debugging flag to xar +- to determine valid compression types. This will skip incorrectly if a +- custom xar is used on OS X, or if a custom xar on another platform is +- built without bzip2 or lzma. +- ++ Raises TestCaseSkipError if the compression type is not compiled in. + """ +- if sys.platform == "darwin" and type == "lzma": ++ if not _check_compression_supported(type): + raise TestCaseSkipError("{t} support not compiled in".format(t=type)) + + @contextlib.contextmanager +@@ -43,6 +94,22 @@ def directory_created(directory_path): + if os.path.exists(directory_path): + shutil.rmtree(directory_path) + ++@contextlib.contextmanager ++def test_directory_created(directory_path): ++ """ ++ Like directory_created, but populates the directory with test files. ++ """ ++ with directory_created(directory_path) as directory: ++ with open(os.path.join(directory, "script"), "w+", opener=lambda path, flags: os.open(path, flags, 0o750)) as f: ++ f.write("#!/bin/sh\necho hello world") ++ with open(os.path.join(directory, "random_1kb"), "wb+") as f: ++ f.write(os.urandom(1000)) ++ with open(os.path.join(directory, "random_4kib"), "wb+") as f: ++ f.write(os.urandom(4096)) ++ with open(os.path.join(directory, "random_1mb"), "wb+") as f: ++ f.write(os.urandom(9999999)) ++ yield directory ++ + @contextlib.contextmanager + def archive_created(archive_path, content_path, *extra_args, **extra_kwargs): + """ +@@ -68,7 +135,7 @@ def archive_created(archive_path, content_path, *extra_args, **extra_kwargs): + HASH_CHUNK_SIZE = 32768 + + def _md5_path(path): +- with open(path, "r") as f: ++ with open(path, "rb") as f: + h = hashlib.md5() + while True: + last = f.read(HASH_CHUNK_SIZE) +@@ -122,7 +189,7 @@ def assert_identical_directories(path1, path2): + + # Sizes and the like + assert stat1.st_size == stat2.st_size, "size mismatch for \"{e1}\" ({s1}) and \"{e2}\" ({s2})".format(e1=entry1, s1=stat1.st_size, e2=entry2, s2=stat2.st_size) +- assert stat1.st_mtime == stat2.st_mtime, "mtime mismatch for \"{e1}\" and \"{e2}\"".format(e1=entry1, e2=entry2) ++ assert int(stat1.st_mtime) == int(stat2.st_mtime), "mtime mismatch for \"{e1}\" and \"{e2}\"".format(e1=entry1, e2=entry2) + assert _md5_path(entry1) == _md5_path(entry2), "md5 hash mismatch for \"{e1}\" and \"{e2}\"".format(e1=entry1, e2=entry2) + if os.path.isdir(entry1): + assert_identical_directories(entry1, entry2) +diff --git a/xar/test/validate.c b/xar/test/validate.c +index dfe69eb..a5fbe37 100644 +--- a/xar/test/validate.c ++++ b/xar/test/validate.c +@@ -16,37 +16,40 @@ + + off_t HeapOff = 0; + +-static char* xar_format_md5(const unsigned char* m) { ++static char* xar_format_sha1(const unsigned char* m) { + char* result = NULL; + asprintf(&result, + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" ++ "%02x%02x%02x%02x" + "%02x%02x%02x%02x", + m[0], m[1], m[2], m[3], + m[4], m[5], m[6], m[7], + m[8], m[9], m[10], m[11], +- m[12], m[13], m[14], m[15]); ++ m[12], m[13], m[14], m[15], ++ m[16], m[17], m[18], m[19]); + return result; + } + + void heap_check(int fd, const char *name, const char *prop, off_t offset, off_t length, const char *csum) { + char *buf; +- EVP_MD_CTX ctx; ++ EVP_MD_CTX *ctx; + const EVP_MD *md; +- unsigned char md5str[EVP_MAX_MD_SIZE]; ++ unsigned char sha1str[EVP_MAX_MD_SIZE]; + unsigned int len; + ssize_t r; +- char *formattedmd5; ++ char *formattedsha1; + + fprintf(stderr, "Heap checking %s %s at offset: %" PRIu64 "\n", name, prop, HeapOff+offset); + OpenSSL_add_all_digests(); +- md = EVP_get_digestbyname("md5"); ++ md = EVP_get_digestbyname("sha1"); + if( md == NULL ) { +- fprintf(stderr, "No md5 digest in openssl\n"); ++ fprintf(stderr, "No sha1 digest in openssl\n"); + exit(1); + } +- EVP_DigestInit(&ctx, md); ++ ctx = EVP_MD_CTX_create(); ++ EVP_DigestInit(ctx, md); + + buf = malloc(length); + if( !buf ) { +@@ -65,14 +68,15 @@ void heap_check(int fd, const char *name, const char *prop, off_t offset, off_t + fprintf(stderr, "Error reading from the heap\n"); + exit(1); + } +- EVP_DigestUpdate(&ctx, buf, length); +- EVP_DigestFinal(&ctx, md5str, &len); ++ EVP_DigestUpdate(ctx, buf, length); ++ EVP_DigestFinal(ctx, sha1str, &len); ++ EVP_MD_CTX_destroy(ctx); + +- formattedmd5 = xar_format_md5(md5str); +- if( strcmp(formattedmd5, csum) != 0 ) { +- fprintf(stderr, "%s %s checksum does not match\n", name, prop); ++ formattedsha1 = xar_format_sha1(sha1str); ++ if( strcmp(formattedsha1, csum) != 0 ) { ++ fprintf(stderr, "%s %s checksum does not match (got %s but expected %s)\n", name, prop, formattedsha1, csum); + } +- free(formattedmd5); ++ free(formattedsha1); + free(buf); + } + +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0002-Update-for-modern-liblzma5-versions.patch b/pkgs/by-name/xa/xar/patches/0002-Update-for-modern-liblzma5-versions.patch new file mode 100644 index 000000000000000..3480585339e5217 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0002-Update-for-modern-liblzma5-versions.patch @@ -0,0 +1,153 @@ +From 6fecd2f5034acaa2b02e98c97a774400ccb2692b Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 16:34:17 +0300 +Subject: [PATCH 02/18] Update for modern liblzma5 versions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This change updates liblzma usage for modern xz versions (≥ 5, that is, +released less than a decade ago). + +It also fixes missing realloc buffer calls that were supposed to be +there but were lost in xar-420 (and Apple does not ship xar with LZMA +support so nobody noticed). See also the offending commit: +https://github.com/apple-oss-distributions/xar/commit/2426082efec74e9ed545cc4f5812ad16322bdf2c +--- + xar/lib/lzmaxar.c | 65 ++++++++--------------------------------------- + 1 file changed, 10 insertions(+), 55 deletions(-) + +diff --git a/xar/lib/lzmaxar.c b/xar/lib/lzmaxar.c +index ba9c868..8dcb484 100644 +--- a/xar/lib/lzmaxar.c ++++ b/xar/lib/lzmaxar.c +@@ -54,27 +54,12 @@ + + #ifdef HAVE_LIBLZMA + +-#ifndef UINT32_C +-#define UINT32_C(v) (v ## U) /* from normally */ +-#endif +-#ifndef LZMA_VERSION +-#define LZMA_VERSION UINT32_C(40420000) /* = 4.42.0alpha6 */ +-#endif +- + struct _lzma_context{ + uint8_t lzmacompressed; + lzma_stream lzma; +- lzma_options_stream options; +- lzma_allocator allocator; +-#if LZMA_VERSION < 40420010U +- lzma_memory_limitter *limit; +-#else +- lzma_memlimit *limit; +-#endif + }; + + #define preset_level 7 +-#define memory_limit 93*1024*1024 /* 1=1M, 5=24M, 6=39M, 7=93M, 8=185M, 9=369M */ + + #define LZMA_CONTEXT(x) ((struct _lzma_context *)(*x)) + #endif +@@ -116,9 +101,7 @@ int xar_lzma_fromheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_t + if( !opt ) return 0; + if( strcmp(opt, "application/x-lzma") != 0 ) return 0; + +- lzma_init_decoder(); +- LZMA_CONTEXT(context)->lzma = LZMA_STREAM_INIT_VAR; +- r = lzma_stream_decoder(&LZMA_CONTEXT(context)->lzma, NULL, NULL); ++ r = lzma_stream_decoder(&LZMA_CONTEXT(context)->lzma, UINT64_MAX, LZMA_CONCATENATED); + if( (r != LZMA_OK) ) { + xar_err_new(x); + xar_err_set_file(x, f); +@@ -194,11 +177,6 @@ int xar_lzma_toheap_done(xar_t x, xar_file_t f, xar_prop_t p, void **context) { + + if( LZMA_CONTEXT(context)->lzmacompressed){ + lzma_end(&LZMA_CONTEXT(context)->lzma); +-#if LZMA_VERSION < 40420010U +- lzma_memory_limitter_end(LZMA_CONTEXT(context)->limit, 1); +-#else +- lzma_memlimit_end(LZMA_CONTEXT(context)->limit, 1); +-#endif + + tmpp = xar_prop_pset(f, p, "encoding", NULL); + if( tmpp ) +@@ -222,7 +200,7 @@ int32_t xar_lzma_toheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_ + + /* on first run, we init the context and check the compression type */ + if( !LZMA_CONTEXT(context) ) { +- int level = preset_level; ++ uint32_t level = preset_level; + *context = calloc(1,sizeof(struct _lzma_context)); + + opt = xar_opt_get(x, XAR_OPT_COMPRESSION); +@@ -243,35 +221,7 @@ int32_t xar_lzma_toheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_ + } + } + +- lzma_init_encoder(); +- LZMA_CONTEXT(context)->options.check = LZMA_CHECK_CRC64; +- LZMA_CONTEXT(context)->options.has_crc32 = 1; /* true */ +- LZMA_CONTEXT(context)->options.alignment = 0; +-#if defined (__ppc__) || defined (powerpc) || defined (__ppc64__) +- LZMA_CONTEXT(context)->options.filters[0].id = LZMA_FILTER_POWERPC; +-#elif defined (__i386__) || defined (__amd64__) || defined(__x86_64__) +- LZMA_CONTEXT(context)->options.filters[0].id = LZMA_FILTER_X86; +-#else +- LZMA_CONTEXT(context)->options.filters[0].id = LZMA_FILTER_COPY; +-#endif +- LZMA_CONTEXT(context)->options.filters[0].options = NULL; +- LZMA_CONTEXT(context)->options.filters[1].id = LZMA_FILTER_LZMA; +- LZMA_CONTEXT(context)->options.filters[1].options = (lzma_options_lzma *)(lzma_preset_lzma + level - 1); +- /* Terminate the filter options array. */ +- LZMA_CONTEXT(context)->options.filters[2].id = UINT64_MAX; +- LZMA_CONTEXT(context)->lzma = LZMA_STREAM_INIT_VAR; +-#if LZMA_VERSION < 40420010U +- LZMA_CONTEXT(context)->limit = lzma_memory_limitter_create(memory_limit); +- LZMA_CONTEXT(context)->allocator.alloc = (void*) lzma_memory_alloc; +- LZMA_CONTEXT(context)->allocator.free = (void*) lzma_memory_free; +-#else +- LZMA_CONTEXT(context)->limit = lzma_memlimit_create(memory_limit); +- LZMA_CONTEXT(context)->allocator.alloc = (void*) lzma_memlimit_alloc; +- LZMA_CONTEXT(context)->allocator.free = (void*) lzma_memlimit_free; +-#endif +- LZMA_CONTEXT(context)->allocator.opaque = LZMA_CONTEXT(context)->limit; +- LZMA_CONTEXT(context)->lzma.allocator = &LZMA_CONTEXT(context)->allocator; +- r = lzma_stream_encoder_single(&LZMA_CONTEXT(context)->lzma, &(LZMA_CONTEXT(context)->options)); ++ r = lzma_easy_encoder(&LZMA_CONTEXT(context)->lzma, level, LZMA_CHECK_CRC64); + if( (r != LZMA_OK) ) { + xar_err_new(x); + xar_err_set_file(x, f); +@@ -279,6 +229,7 @@ int32_t xar_lzma_toheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_ + xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_CREATION); + return -1; + } ++ + LZMA_CONTEXT(context)->lzmacompressed = 1; + if( *inlen == 0 ) + return 0; +@@ -303,7 +254,8 @@ int32_t xar_lzma_toheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_ + outlen = newlen; + else + abort(); /* Someone has somehow malloced over 2^64 bits of ram. */ +- ++ ++ out = realloc(out, outlen); + if( out == NULL ) abort(); + + LZMA_CONTEXT(context)->lzma.next_out = ((unsigned char *)out) + offset; +@@ -318,7 +270,10 @@ int32_t xar_lzma_toheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_ + if (newlen > outlen) + outlen = newlen; + else +- abort(); /* Someone has somehow malloced over 2^64 bits of ram. */ if( out == NULL ) abort(); ++ abort(); /* Someone has somehow malloced over 2^64 bits of ram. */ ++ ++ out = realloc(out, outlen); ++ if( out == NULL ) abort(); + + LZMA_CONTEXT(context)->lzma.next_out = ((unsigned char *)out) + offset; + LZMA_CONTEXT(context)->lzma.avail_out = outlen - offset; +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0003-Fix-undefined-EXT2_ECOMPR_FL-for-e2fsprogs.patch b/pkgs/by-name/xa/xar/patches/0003-Fix-undefined-EXT2_ECOMPR_FL-for-e2fsprogs.patch new file mode 100644 index 000000000000000..79d106a548e068e --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0003-Fix-undefined-EXT2_ECOMPR_FL-for-e2fsprogs.patch @@ -0,0 +1,39 @@ +From 2cbdce329801096c77ab76e6c4154c4ed758f29a Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 18:25:48 +0300 +Subject: [PATCH 03/18] Fix undefined EXT2_ECOMPR_FL for e2fsprogs + +See https://github.com/mackyle/xar/issues/10 +--- + xar/lib/ext2.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/xar/lib/ext2.c b/xar/lib/ext2.c +index 767891a..2380846 100644 +--- a/xar/lib/ext2.c ++++ b/xar/lib/ext2.c +@@ -139,8 +139,10 @@ int xar_ext2attr_archive(xar_t x, xar_file_t f, const char* file, const char *bu + if(! (flags & ~EXT2_NOCOMPR_FL) ) + x_addprop(f, "NoCompBlock"); + #endif ++#ifdef EXT2_ECOMPR_FL + if(! (flags & ~EXT2_ECOMPR_FL) ) + x_addprop(f, "CompError"); ++#endif + if(! (flags & ~EXT2_BTREE_FL) ) + x_addprop(f, "BTree"); + if(! (flags & ~EXT2_INDEX_FL) ) +@@ -225,8 +227,10 @@ int xar_ext2attr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, + if( e2prop_get(f, "NoCompBlock", (char **)&tmp) == 0 ) + flags |= EXT2_NOCOMPR_FL ; + #endif ++#ifdef EXT2_ECOMPR_FL + if( e2prop_get(f, "CompError", (char **)&tmp) == 0 ) + flags |= EXT2_ECOMPR_FL ; ++#endif + if( e2prop_get(f, "BTree", (char **)&tmp) == 0 ) + flags |= EXT2_BTREE_FL ; + if( e2prop_get(f, "HashIndexed", (char **)&tmp) == 0 ) +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0004-Fix-compatibility-with-openssl-1.0.patch b/pkgs/by-name/xa/xar/patches/0004-Fix-compatibility-with-openssl-1.0.patch new file mode 100644 index 000000000000000..f3db8f66abb5760 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0004-Fix-compatibility-with-openssl-1.0.patch @@ -0,0 +1,60 @@ +From f87dc3e8aa8e03722ebc4267aac44d239b0fdbc9 Mon Sep 17 00:00:00 2001 +From: Fabian Groffen +Date: Tue, 1 Jan 2019 18:00:08 +0100 +Subject: [PATCH 04/18] Fix compatibility with openssl-1.0 + +Patch-Source: https://github.com/gentoo/gentoo/blob/dce914f2bbf52360f45c90d877857df3c4c2a353/app-arch/xar/files/xar-1.8-openssl-1.1.patch +-- +lib/hash.c: fix compilation with OpenSSL-1.1+ + +EVP_MD_CTX has become an anonymous struct now, so can't allocate size +for it anymore. +--- + xar/lib/hash.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/xar/lib/hash.c b/xar/lib/hash.c +index 66876ad..cb4f6cf 100644 +--- a/xar/lib/hash.c ++++ b/xar/lib/hash.c +@@ -97,7 +97,7 @@ struct __xar_hash_t { + #ifdef __APPLE__ + CCDigestRef digest; + #else +- EVP_MD_CTX digest; ++ EVP_MD_CTX *digest; + const EVP_MD *type; + #endif + unsigned int length; +@@ -118,7 +118,8 @@ xar_hash_t xar_hash_new(const char *digest_name, void *context) { + #else + OpenSSL_add_all_digests(); + HASH_CTX(hash)->type = EVP_get_digestbyname(digest_name); +- EVP_DigestInit(&HASH_CTX(hash)->digest, HASH_CTX(hash)->type); ++ HASH_CTX(hash)->digest = EVP_MD_CTX_create(); ++ EVP_DigestInit(HASH_CTX(hash)->digest, HASH_CTX(hash)->type); + #endif + + HASH_CTX(hash)->digest_name = strdup(digest_name); +@@ -138,7 +139,7 @@ void xar_hash_update(xar_hash_t hash, void *buffer, size_t nbyte) { + #ifdef __APPLE__ + CCDigestUpdate(HASH_CTX(hash)->digest, buffer, nbyte); + #else +- EVP_DigestUpdate(&HASH_CTX(hash)->digest, buffer, nbyte); ++ EVP_DigestUpdate(HASH_CTX(hash)->digest, buffer, nbyte); + #endif + } + +@@ -155,7 +156,8 @@ void *xar_hash_finish(xar_hash_t hash, size_t *nbyte) { + CCDigestFinal(HASH_CTX(hash)->digest, buffer); + CCDigestDestroy(HASH_CTX(hash)->digest); + #else +- EVP_DigestFinal(&HASH_CTX(hash)->digest, buffer, &HASH_CTX(hash)->length); ++ EVP_DigestFinal(HASH_CTX(hash)->digest, buffer, &HASH_CTX(hash)->length); ++ EVP_MD_CTX_destroy(HASH_CTX(hash)->digest); + #endif + + *nbyte = HASH_CTX(hash)->length; +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0005-Fix-configure.ac-for-Linux-headers.patch b/pkgs/by-name/xa/xar/patches/0005-Fix-configure.ac-for-Linux-headers.patch new file mode 100644 index 000000000000000..63f99b1c0f4921e --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0005-Fix-configure.ac-for-Linux-headers.patch @@ -0,0 +1,123 @@ +From e3357aef21e9de19b40f909f4f7d4416d365d10d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?S=C3=B6ren=20Tempel?= +Date: Sat, 2 Mar 2024 01:25:52 +0100 +Subject: [PATCH 05/18] Fix configure.ac for Linux headers + +Patch-Source: https://github.com/gentoo/gentoo/blob/dce914f2bbf52360f45c90d877857df3c4c2a353/app-arch/xar/files/xar-1.8.0.0.452-linux.patch +--- + xar/configure.ac | 19 +++++++++++++++++-- + xar/include/config.h.in | 3 +++ + xar/lib/util.c | 15 +++++++++++++++ + 3 files changed, 35 insertions(+), 2 deletions(-) + +diff --git a/xar/configure.ac b/xar/configure.ac +index 3a36f42..26d41a5 100644 +--- a/xar/configure.ac ++++ b/xar/configure.ac +@@ -183,7 +183,7 @@ AC_SUBST([enable_autogen]) + + AC_TRY_COMPILE([#include + #include ], [acl_t a], [AC_DEFINE([HAVE_SYS_ACL_H],[1], [define if you have sys/acl.h and it has a working acl_t type])]) +-AC_CHECK_HEADERS(ext2fs/ext2_fs.h sys/statfs.h sys/xattr.h sys/param.h sys/extattr.h libutil.h) ++AC_CHECK_HEADERS(ext2fs/ext2_fs.h sys/statfs.h sys/vfs.h sys/xattr.h sys/param.h sys/extattr.h libutil.h) + AC_CHECK_FUNCS(lgetxattr) + AC_CHECK_FUNCS(lsetxattr) + AC_CHECK_FUNCS(getxattr) +@@ -199,7 +199,22 @@ AC_CHECK_FUNCS(strmode) + + AC_CHECK_MEMBERS([struct statfs.f_fstypename],,,[#include + #include +-#include ]) ++#include ++#ifdef HAVE_SYS_VFS_H ++#include ++#endif]) ++AC_CHECK_MEMBERS([struct statfs.f_iosize],,,[#include ++#include ++#include ++#ifdef HAVE_SYS_VFS_H ++#include ++#endif]) ++AC_CHECK_MEMBERS([struct statfs.f_bsize],,,[#include ++#include ++#include ++#ifdef HAVE_SYS_VFS_H ++#include ++#endif]) + AC_CHECK_MEMBERS([struct statvfs.f_fstypename],,,[#include ]) + AC_CHECK_MEMBERS([struct stat.st_flags]) + +diff --git a/xar/include/config.h.in b/xar/include/config.h.in +index 2bb997b..16c72d3 100644 +--- a/xar/include/config.h.in ++++ b/xar/include/config.h.in +@@ -1,4 +1,5 @@ + #undef HAVE_SYS_STATFS_H ++#undef HAVE_SYS_VFS_H + #undef HAVE_SYS_XATTR_H + #undef HAVE_SYS_EXTATTR_H + #undef HAVE_SYS_PARAM_H +@@ -15,6 +16,8 @@ + #undef HAVE_STRUCT_STAT_ST_FLAGS + #undef HAVE_STRUCT_STATVFS_F_FSTYPENAME + #undef HAVE_STRUCT_STATFS_F_FSTYPENAME ++#undef HAVE_STRUCT_STATFS_F_IOSIZE ++#undef HAVE_STRUCT_STATFS_F_BSIZE + #undef HAVE_SYS_ACL_H + #undef HAVE_LIBUTIL_H + #undef HAVE_LIBPTHREAD +diff --git a/xar/lib/util.c b/xar/lib/util.c +index 0ea661a..1db2daa 100644 +--- a/xar/lib/util.c ++++ b/xar/lib/util.c +@@ -35,11 +35,16 @@ + * Christopher Ryan + */ + ++#include "config.h" ++ + #include + #include + #include + #include + #include ++#ifdef HAVE_SYS_VFS_H ++# include ++#endif + #include + #include + #include +@@ -583,6 +588,14 @@ char *xar_get_mtime(xar_t x, xar_file_t f) { + return tmp; + } + ++#ifndef HAVE_STRUCT_STATFS_F_IOSIZE ++# ifdef HAVE_STRUCT_STATFS_F_BSIZE ++# define f_iosize f_bsize ++# else ++# error need a field to get optimal transfer block size ++# endif ++#endif ++ + size_t xar_optimal_io_size_at_path(const char *path) + { + // Start at 1MiB +@@ -599,6 +612,7 @@ size_t xar_optimal_io_size_at_path(const char *path) + fs_iosize = optimal_rsize; + } + ++#ifdef MNT_LOCAL + // If we're a remote filesystem, never let us go below the optimal size above of 1MiB + // NFS is horrible and lies that the optimal size is 512 bytes. + // Whereas SMB in my testing returns 7MiBs (far more practicle) +@@ -611,6 +625,7 @@ size_t xar_optimal_io_size_at_path(const char *path) + } + } + else ++#endif + { + optimal_rsize = fs_iosize; + } +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0006-Fix-more-non-Darwin-stuff.patch b/pkgs/by-name/xa/xar/patches/0006-Fix-more-non-Darwin-stuff.patch new file mode 100644 index 000000000000000..eb37085ad54d969 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0006-Fix-more-non-Darwin-stuff.patch @@ -0,0 +1,38 @@ +From 9edc1849e05a87c1d397aed437b23f9eef87317f Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 18:38:10 +0300 +Subject: [PATCH 06/18] Fix more non-Darwin stuff + +--- + xar/include/xar.h.in | 1 + + xar/lib/linuxattr.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xar/include/xar.h.in b/xar/include/xar.h.in +index 9c93798..3d24b4f 100644 +--- a/xar/include/xar.h.in ++++ b/xar/include/xar.h.in +@@ -52,6 +52,7 @@ extern "C" { + #import + #else + #define API_DEPRECATED(...) ++#define API_AVAILABLE(...) + #endif + + #pragma pack(4) +diff --git a/xar/lib/linuxattr.c b/xar/lib/linuxattr.c +index 0fec2bb..58ee6a8 100644 +--- a/xar/lib/linuxattr.c ++++ b/xar/lib/linuxattr.c +@@ -226,7 +226,7 @@ int32_t xar_linuxattr_extract(xar_t x, xar_file_t f, const char* file, char *buf + if( statfs(file, &sfs) != 0 ) { + char *tmp, *bname; + tmp = strdup(file); +- bname = safe_dirname(tmp); ++ bname = xar_safe_dirname(tmp); + statfs(bname, &sfs); + free(tmp); + free(bname); +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0007-replace-initialized-constant-with-define-statement.patch b/pkgs/by-name/xa/xar/patches/0007-replace-initialized-constant-with-define-statement.patch new file mode 100644 index 000000000000000..16bdd249e571cc1 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0007-replace-initialized-constant-with-define-statement.patch @@ -0,0 +1,33 @@ +From c9c9f0934f3767e6d040579d72384b443aa4de0c Mon Sep 17 00:00:00 2001 +From: Fabian Groffen +Date: Sat, 16 Jul 2022 21:34:13 +0200 +Subject: [PATCH 07/18] replace initialized constant with #define statement + +GCC doesn't like this: + +filetree.c:744:9: error: variable-sized object may not be initialized + +Since there's nothing changing at runtime at all, just make the compiler +see it's always going to be 1. + +Patch-Source: https://github.com/gentoo/gentoo/blob/dce914f2bbf52360f45c90d877857df3c4c2a353/app-arch/xar/files/xar-1.8.0.0.487-variable-sized-object.patch +--- + xar/lib/filetree.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xar/lib/filetree.c b/xar/lib/filetree.c +index f31682a..9c30c03 100644 +--- a/xar/lib/filetree.c ++++ b/xar/lib/filetree.c +@@ -752,7 +752,7 @@ int xar_file_equals_file(xar_file_t f1, xar_file_t f2) + size_t fspath1_size = 0, fspath2_size = 0; + size_t ns1_size = 0, ns2_size = 0; + const struct __xar_file_t * child1 = NULL, * child2 = NULL; +- const uint keys_to_ignore_count = 1; ++#define keys_to_ignore_count 1 + char * keys_to_ignore[keys_to_ignore_count] = { "id" }; // ID is allowed ot mismatch + + // If the two pointers match, call it the same. +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0008-Fix-configure.ac-not-finding-AR-with-target-prefix.patch b/pkgs/by-name/xa/xar/patches/0008-Fix-configure.ac-not-finding-AR-with-target-prefix.patch new file mode 100644 index 000000000000000..a814464db7b8265 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0008-Fix-configure.ac-not-finding-AR-with-target-prefix.patch @@ -0,0 +1,37 @@ +From 75d4b5578c165f353e1a040c7d349c6588d0cb04 Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 18:43:38 +0300 +Subject: [PATCH 08/18] Fix configure.ac not finding $AR with target prefix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes AR and RANLIB with target prefix (if not set to absolute paths). +Looks like AC_PATH_PROG doesn’t perform PATH lookups when user overrides +the program via environment variable but sets the value to program name +instead of absolute path. + +Note that LD seems to be unused so we remove it. +--- + xar/configure.ac | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/xar/configure.ac b/xar/configure.ac +index 26d41a5..3d8e5de 100644 +--- a/xar/configure.ac ++++ b/xar/configure.ac +@@ -86,9 +86,8 @@ fi + AC_PROG_CPP + + AC_PROG_INSTALL +-AC_PATH_PROG([LD], [ld], , [$PATH]) +-AC_PATH_PROG([AR], [ar], , [$PATH]) +-AC_PATH_PROG([RANLIB], [ranlib], , [$PATH]) ++AC_PROG_AR ++AC_PROG_RANLIB + AC_PATH_PROG([AUTOCONF], [autoconf], , [$PATH]) + + dnl Some libtool envy +-- +2.44.1 + diff --git a/pkgs/tools/compression/xar/0001-Add-useless-descriptions-to-AC_DEFINE.patch b/pkgs/by-name/xa/xar/patches/0009-Add-useless-descriptions-to-AC_DEFINE.patch similarity index 70% rename from pkgs/tools/compression/xar/0001-Add-useless-descriptions-to-AC_DEFINE.patch rename to pkgs/by-name/xa/xar/patches/0009-Add-useless-descriptions-to-AC_DEFINE.patch index a605d2db1708e96..a758938c18e7e02 100644 --- a/pkgs/tools/compression/xar/0001-Add-useless-descriptions-to-AC_DEFINE.patch +++ b/pkgs/by-name/xa/xar/patches/0009-Add-useless-descriptions-to-AC_DEFINE.patch @@ -1,18 +1,18 @@ -From a14be07c0aae3bf6f732d1ca5f625ba375702121 Mon Sep 17 00:00:00 2001 +From d8ef58ec8adde41ba0bd1757c95983ea9e765491 Mon Sep 17 00:00:00 2001 From: Andrew Childs Date: Sun, 15 Nov 2020 19:12:33 +0900 -Subject: [PATCH 1/2] Add useless descriptions to AC_DEFINE +Subject: [PATCH 09/18] Add useless descriptions to AC_DEFINE -Removes autoheader warnings. +Removes autoheader warnings from autoreconfHook. --- - configure.ac | 42 +++++++++++++++++++++--------------------- - 1 file changed, 21 insertions(+), 21 deletions(-) + xar/configure.ac | 46 +++++++++++++++++++++++----------------------- + 1 file changed, 23 insertions(+), 23 deletions(-) -diff --git a/configure.ac b/configure.ac -index 812b5ff..358ab89 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -210,48 +210,48 @@ AC_CHECK_MEMBERS([struct stat.st_flags]) +diff --git a/xar/configure.ac b/xar/configure.ac +index 3d8e5de..0cc04dd 100644 +--- a/xar/configure.ac ++++ b/xar/configure.ac +@@ -219,48 +219,48 @@ AC_CHECK_MEMBERS([struct stat.st_flags]) AC_CHECK_SIZEOF(uid_t) if test $ac_cv_sizeof_uid_t = "4"; then @@ -81,7 +81,7 @@ index 812b5ff..358ab89 100644 else AC_ERROR(can not detect the size of your system's dev_t type) fi -@@ -261,7 +261,7 @@ AC_CHECK_LIB(acl, acl_get_file) +@@ -270,7 +270,7 @@ AC_CHECK_LIB(acl, acl_get_file) dnl Check for paths AC_PREFIX_DEFAULT(/usr/local) @@ -90,6 +90,24 @@ index 812b5ff..358ab89 100644 dnl dnl Configure libxml2. +@@ -350,7 +350,7 @@ have_libbz2="1" + AC_CHECK_HEADERS([bzlib.h], , [have_libbz2="0"]) + AC_CHECK_LIB([bz2], [BZ2_bzCompress], , [have_libbz2="0"]) + if test "x${have_libbz2}" = "x1" ; then +- AC_DEFINE([HAVE_LIBBZ2]) ++ AC_DEFINE([HAVE_LIBBZ2], [], [HAVE_LIBBZ2]) + fi + + dnl +@@ -360,7 +360,7 @@ have_libpthread="1" + AC_CHECK_HEADERS([pthread.h], , [have_pthread="0"]) + AC_CHECK_LIB([pthread], [pthread_mutex_lock], , [have_pthread="0"]) + if test "x${have_pthread}" = "x1" ; then +- AC_DEFINE([HAVE_PTHREAD]) ++ AC_DEFINE([HAVE_PTHREAD], [], [HAVE_PTHREAD]) + fi + + dnl -- -2.28.0 +2.44.1 diff --git a/pkgs/tools/compression/xar/0002-Use-pkg-config-for-libxml2.patch b/pkgs/by-name/xa/xar/patches/0010-Update-configure.ac-for-openssl-libxml2-liblzma-and-.patch similarity index 51% rename from pkgs/tools/compression/xar/0002-Use-pkg-config-for-libxml2.patch rename to pkgs/by-name/xa/xar/patches/0010-Update-configure.ac-for-openssl-libxml2-liblzma-and-.patch index d71ad4b753c17e4..61d81a327281f83 100644 --- a/pkgs/tools/compression/xar/0002-Use-pkg-config-for-libxml2.patch +++ b/pkgs/by-name/xa/xar/patches/0010-Update-configure.ac-for-openssl-libxml2-liblzma-and-.patch @@ -1,21 +1,31 @@ -From 276833851657c85651c053ee16b8e1a8dc768a50 Mon Sep 17 00:00:00 2001 -From: Andrew Childs -Date: Sun, 15 Nov 2020 19:12:56 +0900 -Subject: [PATCH 2/2] Use pkg-config for libxml2 +From 7397c0d8b290d8c202806cea6078b46aa4ddd3db Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 18:58:14 +0300 +Subject: [PATCH 10/18] Update configure.ac for openssl, libxml2, liblzma and + musl-fts +Simplifies libxml2 detection, adds detection for liblzma (from xz), +openssl and fts (for musl libc). --- - configure.ac | 66 +++++++++------------------------------------------- - 1 file changed, 11 insertions(+), 55 deletions(-) + xar/configure.ac | 83 +++++++++++++++++------------------------------- + 1 file changed, 30 insertions(+), 53 deletions(-) -diff --git a/configure.ac b/configure.ac -index 358ab89..984a694 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -268,61 +268,17 @@ dnl Configure libxml2. - dnl - LIBXML2_VERSION_MIN=2.6.11 +diff --git a/xar/configure.ac b/xar/configure.ac +index 0cc04dd..e466ee0 100644 +--- a/xar/configure.ac ++++ b/xar/configure.ac +@@ -272,63 +272,14 @@ AC_PREFIX_DEFAULT(/usr/local) + + AC_CHECK_FUNC([asprintf], AC_DEFINE([HAVE_ASPRINTF], [], [HAVE_ASPRINTF])) --have_libxml2="1" ++AC_SEARCH_LIBS([fts_close], [fts]) ++ + dnl + dnl Configure libxml2. + dnl +-LIBXML2_VERSION_MIN=2.6.11 +- + have_libxml2="1" - -AC_ARG_WITH([xml2-config], [ --with-xml2-config libxml2 config program], -if test "x${with_xml2_config}" = "xno" ; then @@ -67,23 +77,51 @@ index 358ab89..984a694 100644 - dnl Final sanity check, to make sure that xmlwriter is present. - AC_CHECK_HEADER([libxml/xmlwriter.h], , [have_libxml2="0"]) -fi --if test "x${have_libxml2}" = "x0" ; then -- AC_MSG_ERROR([Cannot build without libxml2]) --fi -+PKG_PROG_PKG_CONFIG ++AC_CHECK_HEADERS([libxml/xmlwriter.h], , [have_libxml2="0"]) ++AC_CHECK_LIB([xml2], [xmlInitParser], , [have_libxml2="0"]) + if test "x${have_libxml2}" = "x0" ; then + AC_MSG_ERROR([Cannot build without libxml2]) + fi +@@ -343,6 +294,22 @@ if test "x${have_libz}" = "x0" ; then + AC_MSG_ERROR([Cannot build without libz]) + fi + ++dnl ++dnl Configure openssl. ++dnl ++have_openssl="1" ++AC_CHECK_HEADERS([openssl/evp.h], , [have_openssl="0"]) ++AC_CHECK_LIB([crypto], [OPENSSL_config], , [have_openssl="0"]) ++if test "x${have_openssl}" = "x0" ; then ++ case "${host}" in ++ *-*-darwin*) ++ ;; ++ *) ++ AC_MSG_ERROR([Cannot build without OpenSSL for non-Darwin host]) ++ ;; ++ esac ++fi + -+PKG_CHECK_MODULES(LIBXML2_PKGCONFIG, [libxml-2.0 >= ${LIBXML2_VERSION_MIN}], -+ [ -+ have_libxml2=1 -+ CPPFLAGS="${CPPFLAGS} ${LIBXML2_PKGCONFIG_CFLAGS}" -+ LIBS="${LIBS} ${LIBXML2_PKGCONFIG_LIBS}" -+ ], -+ [ -+ have_libxml2=0 -+ ]) + dnl + dnl Configure libbz2. + dnl +@@ -353,6 +320,16 @@ if test "x${have_libbz2}" = "x1" ; then + AC_DEFINE([HAVE_LIBBZ2], [], [HAVE_LIBBZ2]) + fi ++dnl ++dnl Configure liblzma. ++dnl ++have_liblzma="1" ++AC_CHECK_HEADERS([lzma.h], , [have_liblzma="0"]) ++AC_CHECK_LIB([lzma], [lzma_stream_decoder], , [have_liblzma="0"]) ++if test "x${have_liblzma}" = "x1" ; then ++ AC_DEFINE([HAVE_LIBLZMA], [], [HAVE_LIBLZMA]) ++fi ++ + dnl + dnl Configure libpthread. dnl - dnl Configure libcrypto (part of OpenSSL). -- -2.28.0 +2.44.1 diff --git a/pkgs/by-name/xa/xar/patches/0011-Fix-missing-includes-and-silence-string-format-warni.patch b/pkgs/by-name/xa/xar/patches/0011-Fix-missing-includes-and-silence-string-format-warni.patch new file mode 100644 index 000000000000000..c0568a1772e10f0 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0011-Fix-missing-includes-and-silence-string-format-warni.patch @@ -0,0 +1,104 @@ +From 10bd40f42f6ffe4b4a6402aca761f6ce46068938 Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 19:10:46 +0300 +Subject: [PATCH 11/18] Fix missing includes and silence string format warnings + +Based on patch from Gentoo; see +https://gitweb.gentoo.org/repo/gentoo.git/plain/app-arch/xar/files/xar-1.8.0.0.498-impl-decls.patch?id=cc91eb0f86043ae92c10cce55b326244bed3f061 +--- + xar/lib/Makefile.inc.in | 1 + + xar/lib/darwinattr.c | 1 + + xar/lib/ea.c | 3 ++- + xar/lib/ext2.c | 1 + + xar/lib/util.c | 1 + + xar/src/xar_internal.h | 4 ---- + 6 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/xar/lib/Makefile.inc.in b/xar/lib/Makefile.inc.in +index c046b25..d5e9003 100644 +--- a/xar/lib/Makefile.inc.in ++++ b/xar/lib/Makefile.inc.in +@@ -127,6 +127,7 @@ lib_distclean : + + CPPFLAGS := -I@objroot@include $(CPPFLAGS) + CPPFLAGS := -I@srcroot@include $(CPPFLAGS) ++CPPFLAGS := -I@srcroot@lib $(CPPFLAGS) + + # + # Build rules. +diff --git a/xar/lib/darwinattr.c b/xar/lib/darwinattr.c +index 4938965..18302b0 100644 +--- a/xar/lib/darwinattr.c ++++ b/xar/lib/darwinattr.c +@@ -37,6 +37,7 @@ + + #include "config.h" + #include ++#include + #include + #include + #include +diff --git a/xar/lib/ea.c b/xar/lib/ea.c +index 1bb8e27..fa1d06a 100644 +--- a/xar/lib/ea.c ++++ b/xar/lib/ea.c +@@ -29,6 +29,7 @@ + #include "config.h" + #include + #include ++#include /* for PRId64 */ + #include + #include + #include +@@ -67,7 +68,7 @@ xar_ea_t xar_ea_new(xar_file_t f, const char *name) + xar_prop_setvalue(XAR_EA(ret)->prop, NULL); + XAR_PROP(XAR_EA(ret)->prop)->attrs = xar_attr_new(); + XAR_ATTR(XAR_PROP(XAR_EA(ret)->prop)->attrs)->key = strdup("id"); +- asprintf((char **)&XAR_ATTR(XAR_PROP(XAR_EA(ret)->prop)->attrs)->value, "%lld", XAR_FILE(f)->nexteaid++); ++ asprintf((char **)&XAR_ATTR(XAR_PROP(XAR_EA(ret)->prop)->attrs)->value, "%"PRId64, XAR_FILE(f)->nexteaid++); + + xar_prop_pset(f, XAR_EA(ret)->prop, "name", name); + +diff --git a/xar/lib/ext2.c b/xar/lib/ext2.c +index 2380846..b4ca1b0 100644 +--- a/xar/lib/ext2.c ++++ b/xar/lib/ext2.c +@@ -41,6 +41,7 @@ + #include "asprintf.h" + #endif + #include ++#include + #include + #include "xar.h" + #include "arcmod.h" +diff --git a/xar/lib/util.c b/xar/lib/util.c +index 1db2daa..ac0b822 100644 +--- a/xar/lib/util.c ++++ b/xar/lib/util.c +@@ -38,6 +38,7 @@ + #include "config.h" + + #include ++#include + #include + #include + #include +diff --git a/xar/src/xar_internal.h b/xar/src/xar_internal.h +index b78745c..2e6199e 100644 +--- a/xar/src/xar_internal.h ++++ b/xar/src/xar_internal.h +@@ -8,11 +8,7 @@ + #ifndef _XAR_INTERNAL_H_ + #define _XAR_INTERNAL_H_ + +-#ifdef XARSIG_BUILDING_WITH_XAR + #include "xar.h" +-#else +-#include +-#endif // XARSIG_BUILDING_WITH_XAR + + // Undeprecate these for internal usage + xar_t xar_open(const char *file, int32_t flags) API_AVAILABLE(macos(10.4)); +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0012-Fix-char-signedness-for-ARM-and-PowerPC.patch b/pkgs/by-name/xa/xar/patches/0012-Fix-char-signedness-for-ARM-and-PowerPC.patch new file mode 100644 index 000000000000000..722ca7c5d477b1c --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0012-Fix-char-signedness-for-ARM-and-PowerPC.patch @@ -0,0 +1,46 @@ +From 668cdee77b96d6bbc8400880470d9757f83ef7f1 Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 19:26:14 +0300 +Subject: [PATCH 12/18] Fix char signedness for ARM and PowerPC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use signed char explicitly for ARM and PowerPC (defaults to unsigned). +Otherwise -1 integer literal is helpfully converted to char 255… + +Derives from https://gitweb.gentoo.org/repo/gentoo.git/plain/app-arch/xar/files/xar-1.8-arm-ppc.patch?id=cc91eb0f86043ae92c10cce55b326244bed3f061 +--- + xar/lib/b64.c | 2 +- + xar/src/xar.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xar/lib/b64.c b/xar/lib/b64.c +index 6361acd..4ffc34c 100644 +--- a/xar/lib/b64.c ++++ b/xar/lib/b64.c +@@ -59,7 +59,7 @@ typedef enum _B64CommandCodes { + B64_IgnorableCharacter = -1 + } B64CommandCodes; + +-static char b64revtb[256] = { ++static signed char b64revtb[256] = { + -3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*0-15*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16-31*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /*32-47*/ +diff --git a/xar/src/xar.c b/xar/src/xar.c +index 9977e8a..1bceb63 100644 +--- a/xar/src/xar.c ++++ b/xar/src/xar.c +@@ -910,7 +910,7 @@ static void print_version() { + int main(int argc, char *argv[]) { + int ret; + char *filename = NULL; +- char command = 0, c; ++ signed char command = 0, c; + char **args; + const char *tocfile = NULL; + int arglen, i, err; +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0013-Enable-extended-attributes-for-btrfs.patch b/pkgs/by-name/xa/xar/patches/0013-Enable-extended-attributes-for-btrfs.patch new file mode 100644 index 000000000000000..6d7807780a61691 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0013-Enable-extended-attributes-for-btrfs.patch @@ -0,0 +1,43 @@ +From 3cc584baacd970f7eed0051c1562434b7155f9df Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 19:28:09 +0300 +Subject: [PATCH 13/18] Enable extended attributes for btrfs + +--- + xar/lib/linuxattr.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/xar/lib/linuxattr.c b/xar/lib/linuxattr.c +index 58ee6a8..496dd82 100644 +--- a/xar/lib/linuxattr.c ++++ b/xar/lib/linuxattr.c +@@ -80,6 +80,10 @@ + #define XFS_SUPER_MAGIC 0x58465342 + #endif + ++#ifndef BTRFS_SUPER_MAGIC ++#define BTRFS_SUPER_MAGIC 0x9123683E ++#endif ++ + #if defined(HAVE_SYS_XATTR_H) && defined(HAVE_LGETXATTR) && !defined(__APPLE__) + + struct _linuxattr_context{ +@@ -175,6 +179,7 @@ TRYAGAIN: + case JFS_SUPER_MAGIC: fsname = "jfs" ; break; + case REISERFS_SUPER_MAGIC:fsname = "reiser" ; break; + case XFS_SUPER_MAGIC: fsname = "xfs" ; break; ++ case BTRFS_SUPER_MAGIC: fsname = "btrfs" ; break; + default: retval=0; goto BAIL; + }; + +@@ -236,6 +241,7 @@ int32_t xar_linuxattr_extract(xar_t x, xar_file_t f, const char* file, char *buf + case JFS_SUPER_MAGIC: fsname = "jfs" ; break; + case REISERFS_SUPER_MAGIC:fsname = "reiser" ; break; + case XFS_SUPER_MAGIC: fsname = "xfs" ; break; ++ case BTRFS_SUPER_MAGIC:fsname = "btrfs" ; break; + }; + + for(p = xar_prop_pfirst(f); p; p = xar_prop_pnext(p)) { +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0014-Fix-segfault-when-copying-xattr-buffers.patch b/pkgs/by-name/xa/xar/patches/0014-Fix-segfault-when-copying-xattr-buffers.patch new file mode 100644 index 000000000000000..0de21af2f140a23 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0014-Fix-segfault-when-copying-xattr-buffers.patch @@ -0,0 +1,123 @@ +From 694af68cc19a0de2a6204b9cf22be34230c59aa3 Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 20:46:31 +0300 +Subject: [PATCH 14/18] Fix segfault when copying xattr buffers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +xar_linuxattr_read allocates an internal buffer and incrementally copies +the data to xar_attrcopy_to_heap’s inbuf. This change fixes the offset +handling by rewriting xar_linuxattr_read function from scratch (with an +arguably cleaner implementation). +--- + xar/lib/linuxattr.c | 68 +++++++++++++++++++++++++++------------------ + 1 file changed, 41 insertions(+), 27 deletions(-) + +diff --git a/xar/lib/linuxattr.c b/xar/lib/linuxattr.c +index 496dd82..30c85c2 100644 +--- a/xar/lib/linuxattr.c ++++ b/xar/lib/linuxattr.c +@@ -97,39 +97,50 @@ struct _linuxattr_context{ + + #define LINUXATTR_CONTEXT(x) ((struct _linuxattr_context *)(x)) + +-int32_t xar_linuxattr_read(xar_t x, xar_file_t f, void * buf, size_t len, void *context) { +- +- if( !LINUXATTR_CONTEXT(context)->buf ) { +- int r; +- LINUXATTR_CONTEXT(context)->bufsz = 1024; ++int32_t xar_linuxattr_read(xar_t x, xar_file_t f, void *inbuf, size_t len, void *context) { ++ void *buf; ++ int bufsz, off, ret; ++ int r; ++ ++ buf = LINUXATTR_CONTEXT(context)->buf; ++ bufsz = LINUXATTR_CONTEXT(context)->bufsz; ++ off = LINUXATTR_CONTEXT(context)->off; ++ ++ if (buf == NULL) { ++ bufsz = 1024; + AGAIN2: +- LINUXATTR_CONTEXT(context)->buf = malloc(LINUXATTR_CONTEXT(context)->bufsz); +- if(!LINUXATTR_CONTEXT(context)->buf) +- goto AGAIN2; +- memset(LINUXATTR_CONTEXT(context)->buf, 0, LINUXATTR_CONTEXT(context)->bufsz); +- r = lgetxattr(LINUXATTR_CONTEXT(context)->file, LINUXATTR_CONTEXT(context)->attrname, LINUXATTR_CONTEXT(context)->buf, LINUXATTR_CONTEXT(context)->bufsz); +- if( r < 0 ) { +- switch(errno) { +- case ERANGE: LINUXATTR_CONTEXT(context)->bufsz *= 2; free(LINUXATTR_CONTEXT(context)->buf); goto AGAIN2; +- case ENOTSUP: free(LINUXATTR_CONTEXT(context)->buf); return 0; +- default: break; ++ buf = malloc(bufsz); ++ if (!buf) { ++ return -1; ++ } ++ memset(buf, 0, bufsz); ++ r = lgetxattr(LINUXATTR_CONTEXT(context)->file, LINUXATTR_CONTEXT(context)->attrname, buf, bufsz); ++ if (r < 0) { ++ free(buf); ++ switch (errno) { ++ case ERANGE: ++ bufsz *= 2; ++ goto AGAIN2; ++ case ENOTSUP: ++ return 0; + }; + return -1; + } ++ LINUXATTR_CONTEXT(context)->buf = buf; + LINUXATTR_CONTEXT(context)->bufsz = r; ++ bufsz = r; + } + +- if( (LINUXATTR_CONTEXT(context)->bufsz-LINUXATTR_CONTEXT(context)->off) <= len ) { +- int32_t ret; +- ret = LINUXATTR_CONTEXT(context)->bufsz - LINUXATTR_CONTEXT(context)->off; +- memcpy(buf, ((char *)LINUXATTR_CONTEXT(context)->buf)+LINUXATTR_CONTEXT(context)->off, ret); +- LINUXATTR_CONTEXT(context)->off += ret; +- return(ret); +- } else { +- memcpy(buf, ((char *)LINUXATTR_CONTEXT(context)->buf)+LINUXATTR_CONTEXT(context)->off, len); +- LINUXATTR_CONTEXT(context)->buf = ((char *)LINUXATTR_CONTEXT(context)->buf) + len; +- return len; ++ ret = bufsz - off; ++ if (ret <= len) { ++ memcpy(inbuf, ((char *)buf) + off, ret); ++ LINUXATTR_CONTEXT(context)->off = bufsz; ++ return ret; + } ++ ++ memcpy(inbuf, ((char *)buf) + off, len); ++ LINUXATTR_CONTEXT(context)->off += len; ++ return len; + } + + int32_t xar_linuxattr_write(xar_t x, xar_file_t f, void *buf, size_t len, void *context) { +@@ -185,6 +196,7 @@ TRYAGAIN: + + for( i=buf; (i-buf) < ret; i += strlen(i)+1 ) { + xar_ea_t e; ++ int rc; + + context.bufsz = 0; + context.off = 0; +@@ -194,11 +206,13 @@ TRYAGAIN: + xar_ea_pset(f, e, "fstype", fsname); + context.attrname = i; + context.ea = e; +- if (XAR(x)->attrcopy_to_heap(x, f, xar_ea_root(e), xar_linuxattr_read,&context) < 0) { ++ rc = XAR(x)->attrcopy_to_heap(x, f, xar_ea_root(e), xar_linuxattr_read, &context); ++ if (context.buf != NULL) ++ free(context.buf); ++ if (rc < 0) { + retval = -1; + goto BAIL; + } +- free(context.buf); + context.attrname = NULL; + } + +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0015-Fix-segfault-in-xar_attrcopy_from_heap.patch b/pkgs/by-name/xa/xar/patches/0015-Fix-segfault-in-xar_attrcopy_from_heap.patch new file mode 100644 index 000000000000000..40333688fb41c66 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0015-Fix-segfault-in-xar_attrcopy_from_heap.patch @@ -0,0 +1,59 @@ +From 3b85c625c6a9453aa48a697af9db80fbc270592c Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sat, 27 Jul 2024 21:04:20 +0300 +Subject: [PATCH 15/18] Fix segfault in xar_attrcopy_from_heap + +Fixes a nasty segfault crash when extracting files with extended +attributes (and perhaps in other cases). + +xar_attrcopy_from_heap (in lib/io.c) must not assume that context is +convertible to DATA_CONTEXT. Without this change, it calls the callback +from the provided context as if it was DATA_CONTEXT, but the context can +actually be other types, e.g. LINUXATTR_CONTEXT. +--- + xar/lib/data.c | 9 ++++++++- + xar/lib/io.c | 3 --- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/xar/lib/data.c b/xar/lib/data.c +index dcb5783..cfb3d58 100644 +--- a/xar/lib/data.c ++++ b/xar/lib/data.c +@@ -245,6 +245,13 @@ int32_t xar_data_extract(xar_t x, xar_file_t f, const char *file, char *buffer, + return retval; + } + ++static int xar_data_verify_callback(xar_t x, xar_file_t f, void *inbuf, size_t bsize, void *context) { ++ DATA_CONTEXT(context)->total += bsize; ++ if (DATA_CONTEXT(context)->progress) ++ DATA_CONTEXT(context)->progress(x, f, DATA_CONTEXT(context)->total); ++ return 0; ++} ++ + int32_t xar_data_verify(xar_t x, xar_file_t f, xar_progress_callback p) + { + const char *opt; +@@ -269,5 +276,5 @@ int32_t xar_data_verify(xar_t x, xar_file_t f, xar_progress_callback p) + if (!tmpp) // It appears that xar can have truely empty files, aka, no data. We should just fail to verify these files. + return 0; // After all, the checksum of blank is meaningless. So, failing to do so will cause a crash. + +- return XAR(x)->attrcopy_from_heap(x, f, tmpp, NULL , (void *)(&context)); ++ return XAR(x)->attrcopy_from_heap(x, f, tmpp, xar_data_verify_callback, (void *)(&context)); + } +diff --git a/xar/lib/io.c b/xar/lib/io.c +index fb9a72e..64c69af 100644 +--- a/xar/lib/io.c ++++ b/xar/lib/io.c +@@ -529,9 +529,6 @@ int32_t xar_attrcopy_from_heap(xar_t x, xar_file_t f, xar_prop_t p, write_callba + + readsofar += bsize; + +- if (DATA_CONTEXT(context)->progress) +- DATA_CONTEXT(context)->progress(x, f, readsofar); +- + bsize = def_bsize; + } + +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0016-Do-not-set-property-for-empty-ACL.patch b/pkgs/by-name/xa/xar/patches/0016-Do-not-set-property-for-empty-ACL.patch new file mode 100644 index 000000000000000..45d34afed8350ec --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0016-Do-not-set-property-for-empty-ACL.patch @@ -0,0 +1,90 @@ +From 1ce0939ef6e0159dc17a64c28e9c5aa0a47a61a7 Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Sun, 28 Jul 2024 12:00:01 +0300 +Subject: [PATCH 16/18] Do not set property for empty ACL + +On Linux, acl_get_file helpfully converts file mode bits to ACL if no +extended attribute is set. See +https://git.savannah.nongnu.org/cgit/acl.git/tree/libacl/acl_get_file.c?id=d9bb1759d4dad2f28a6dcc8c1742ff75d16dd10d#n83 + +At the same time, Nix sandbox does not filter getxattr syscalls to +return ENOTSUP, but does filter setxattr. So we are in a intricate +situation where acl library thinks that EAs/ACLs are supported and +returns meaningful values for reads, so xar archives files with acl +property, but extraction fails because of the syscall filter. + +As a workaround, we add acl_extended_file check that actually returns +whether the file is associated with ACLs (internally represented as +extended attributes). +--- + xar/configure.ac | 5 ++--- + xar/include/config.h.in | 2 ++ + xar/lib/stat.c | 9 +++++++++ + 3 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/xar/configure.ac b/xar/configure.ac +index e466ee0..c3d9ff7 100644 +--- a/xar/configure.ac ++++ b/xar/configure.ac +@@ -180,9 +180,8 @@ fi + ) + AC_SUBST([enable_autogen]) + +-AC_TRY_COMPILE([#include +-#include ], [acl_t a], [AC_DEFINE([HAVE_SYS_ACL_H],[1], [define if you have sys/acl.h and it has a working acl_t type])]) +-AC_CHECK_HEADERS(ext2fs/ext2_fs.h sys/statfs.h sys/vfs.h sys/xattr.h sys/param.h sys/extattr.h libutil.h) ++AC_CHECK_HEADERS(sys/acl.h acl/libacl.h ext2fs/ext2_fs.h sys/statfs.h sys/vfs.h sys/xattr.h sys/param.h sys/extattr.h libutil.h) ++AC_CHECK_DECLS([acl_extended_file], [], [], [[#include ]]) + AC_CHECK_FUNCS(lgetxattr) + AC_CHECK_FUNCS(lsetxattr) + AC_CHECK_FUNCS(getxattr) +diff --git a/xar/include/config.h.in b/xar/include/config.h.in +index 16c72d3..779f5aa 100644 +--- a/xar/include/config.h.in ++++ b/xar/include/config.h.in +@@ -3,6 +3,7 @@ + #undef HAVE_SYS_XATTR_H + #undef HAVE_SYS_EXTATTR_H + #undef HAVE_SYS_PARAM_H ++#undef HAVE_DECL_ACL_EXTENDED_FILE + #undef HAVE_LGETXATTR + #undef HAVE_LSETXATTR + #undef HAVE_GETXATTR +@@ -12,6 +13,7 @@ + #undef HAVE_CHFLAGS + #undef HAVE_STATVFS + #undef HAVE_STATFS ++#undef HAVE_ACL_LIBACL_H + #undef HAVE_EXT2FS_EXT2_FS_H + #undef HAVE_STRUCT_STAT_ST_FLAGS + #undef HAVE_STRUCT_STATVFS_F_FSTYPENAME +diff --git a/xar/lib/stat.c b/xar/lib/stat.c +index b0cce7c..81771dc 100644 +--- a/xar/lib/stat.c ++++ b/xar/lib/stat.c +@@ -66,6 +66,9 @@ + #ifdef HAVE_SYS_ACL_H + #include + #endif ++#ifdef HAVE_ACL_LIBACL_H ++#include ++#endif + #include "xar.h" + #include "arcmod.h" + #include "archive.h" +@@ -131,6 +134,12 @@ static int32_t aacls(xar_t x, xar_file_t f, const char *file) { + if( !xar_check_prop(x, "acl") ) + return 0; + ++#ifdef HAVE_DECL_ACL_EXTENDED_FILE ++ /* Do nothing if the file is not associated with ACL. */ ++ if( !acl_extended_file(file) ) ++ return 0; ++#endif ++ + a = acl_get_file(file, ACL_TYPE_DEFAULT); + if( a ) { + char *t; +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0017-Fix-time-format-for-musl.patch b/pkgs/by-name/xa/xar/patches/0017-Fix-time-format-for-musl.patch new file mode 100644 index 000000000000000..6237e3c7dff3122 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0017-Fix-time-format-for-musl.patch @@ -0,0 +1,75 @@ +From 244f0b57e137ade241ee57f8118638bb89db4f3d Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Tue, 30 Jul 2024 16:06:57 +0300 +Subject: [PATCH 17/18] Fix time format for musl + +Directive %F is not supported in musl (until recent versions). +https://git.musl-libc.org/cgit/musl/commit/src/time/strptime.c?id=fced99e93daeefb0192fd16304f978d4401d1d77 + +Avoid using it for str[fp]time. +--- + xar/lib/stat.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/xar/lib/stat.c b/xar/lib/stat.c +index 81771dc..d71a613 100644 +--- a/xar/lib/stat.c ++++ b/xar/lib/stat.c +@@ -82,6 +82,8 @@ + #define LLONG_MAX LONG_LONG_MAX + #endif + ++static const char time_format[] = "%Y-%m-%dT%H:%M:%SZ"; ++ + static struct { + const char *name; + mode_t type; +@@ -513,24 +515,21 @@ int32_t xar_stat_archive(xar_t x, xar_file_t f, const char *file, const char *bu + if( xar_check_prop(x, "atime") ) { + gmtime_r(&XAR(x)->sbcache.st_atime, &t); + memset(time, 0, sizeof(time)); +- strftime(time, sizeof(time), "%FT%T", &t); +- strcat(time, "Z"); ++ strftime(time, sizeof(time), time_format, &t); + xar_prop_set(f, "atime", time); + } + + if( xar_check_prop(x, "mtime") ) { + gmtime_r(&XAR(x)->sbcache.st_mtime, &t); + memset(time, 0, sizeof(time)); +- strftime(time, sizeof(time), "%FT%T", &t); +- strcat(time, "Z"); ++ strftime(time, sizeof(time), time_format, &t); + xar_prop_set(f, "mtime", time); + } + + if( xar_check_prop(x, "ctime") ) { + gmtime_r(&XAR(x)->sbcache.st_ctime, &t); + memset(time, 0, sizeof(time)); +- strftime(time, sizeof(time), "%FT%T", &t); +- strcat(time, "Z"); ++ strftime(time, sizeof(time), time_format, &t); + xar_prop_set(f, "ctime", time); + } + +@@ -680,7 +679,7 @@ int32_t xar_set_perm(xar_t x, xar_file_t f, const char *file, char *buffer, size + xar_prop_get(f, "atime", ×tr); + if( timestr ) { + memset(&t, 0, sizeof(t)); +- strptime(timestr, "%FT%T", &t); ++ strptime(timestr, time_format, &t); + tv[ATIME].tv_sec = timegm(&t); + } else { + tv[ATIME].tv_sec = time(NULL); +@@ -689,7 +688,7 @@ int32_t xar_set_perm(xar_t x, xar_file_t f, const char *file, char *buffer, size + xar_prop_get(f, "mtime", ×tr); + if( timestr ) { + memset(&t, 0, sizeof(t)); +- strptime(timestr, "%FT%T", &t); ++ strptime(timestr, time_format, &t); + tv[MTIME].tv_sec = timegm(&t); + } else { + tv[MTIME].tv_sec = time(NULL); +-- +2.44.1 + diff --git a/pkgs/by-name/xa/xar/patches/0018-Replace-memcpy-with-memmove-for-musl.patch b/pkgs/by-name/xa/xar/patches/0018-Replace-memcpy-with-memmove-for-musl.patch new file mode 100644 index 000000000000000..f38bdfa1af9efd5 --- /dev/null +++ b/pkgs/by-name/xa/xar/patches/0018-Replace-memcpy-with-memmove-for-musl.patch @@ -0,0 +1,25 @@ +From c5d4ac4b1f3b1b2e0762812cefc746eb64394f58 Mon Sep 17 00:00:00 2001 +From: Ivan Trubach +Date: Tue, 30 Jul 2024 17:29:06 +0300 +Subject: [PATCH 18/18] Replace memcpy with memmove for musl + +--- + xar/lib/io.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xar/lib/io.c b/xar/lib/io.c +index 64c69af..c962c4b 100644 +--- a/xar/lib/io.c ++++ b/xar/lib/io.c +@@ -650,7 +650,7 @@ static int32_t flush_stream(xar_stream *stream) { + state->pending_buf = NULL; + } else if( state->pending_buf_size > len ) { + state->pending_buf_size -= len; +- memcpy(state->pending_buf, state->pending_buf + len, state->pending_buf_size); ++ memmove(state->pending_buf, state->pending_buf + len, state->pending_buf_size); + } + } + +-- +2.44.1 + diff --git a/pkgs/tools/compression/xar/default.nix b/pkgs/tools/compression/xar/default.nix deleted file mode 100644 index 9c03c41054be9de..000000000000000 --- a/pkgs/tools/compression/xar/default.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ lib, stdenv, fetchurl, pkg-config, libxml2, xz, openssl, zlib, bzip2, fts, autoreconfHook }: - -stdenv.mkDerivation rec { - version = "1.6.1"; - pname = "xar"; - - src = fetchurl { - url = "https://github.com/downloads/mackyle/xar/${pname}-${version}.tar.gz"; - sha256 = "0ghmsbs6xwg1092v7pjcibmk5wkyifwxw6ygp08gfz25d2chhipf"; - }; - - nativeBuildInputs = [ autoreconfHook pkg-config ]; - buildInputs = [ libxml2 xz openssl zlib bzip2 fts ]; - - patches = [ - ./0001-Add-useless-descriptions-to-AC_DEFINE.patch - ./0002-Use-pkg-config-for-libxml2.patch - ]; - - postPatch = '' - substituteInPlace configure.ac \ - --replace 'OpenSSL_add_all_ciphers' 'OPENSSL_init_crypto' \ - --replace 'openssl/evp.h' 'openssl/crypto.h' - ''; - - configureFlags = lib.optional (fts != null) "LDFLAGS=-lfts"; - - meta = { - homepage = "https://mackyle.github.io/xar/"; - description = "Extensible Archiver"; - - longDescription = - '' The XAR project aims to provide an easily extensible archive format. - Important design decisions include an easily extensible XML table of - contents for random access to archived files, storing the toc at the - beginning of the archive to allow for efficient handling of streamed - archives, the ability to handle files of arbitrarily large sizes, the - ability to choose independent encodings for individual files in the - archive, the ability to store checksums for individual files in both - compressed and uncompressed form, and the ability to query the table - of content's rich meta-data. - ''; - - license = lib.licenses.bsd3; - maintainers = with lib.maintainers; [ copumpkin ]; - platforms = lib.platforms.all; - mainProgram = "xar"; - }; -} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index a0d28150f966817..fdaaf001d650fdb 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -14082,8 +14082,6 @@ with pkgs; vul = callPackage ../applications/misc/vul { }; - xar = callPackage ../tools/compression/xar { }; - xarchive = callPackage ../tools/archivers/xarchive { }; xarchiver = callPackage ../tools/archivers/xarchiver { };