patch-shebangs: fix binary data corrupt after patching

This removes the recently introduced shell based implementation of `sponge` which wasn't capable of managing binary input.

Now, a tmpFile under $TMPDIR is created manually and later deleted

see: https://github.com/NixOS/nixpkgs/pull/414448#issuecomment-3041238623

DavHau a1154d63 1cf013f7

Changed files
+59 -28
pkgs
build-support
setup-hooks
test
+20 -28
pkgs/build-support/setup-hooks/patch-shebangs.sh
···
return 0
fi
-
# like sponge from moreutils but in pure bash
-
_sponge() {
-
local content
-
local target
-
local restoreReadOnly
-
content=""
-
target="$1"
-
-
# Make file writable if it is read-only
-
if [[ ! -w "$target" ]]; then
-
chmod +w "$target"
-
restoreReadOnly=true
-
fi
-
-
while IFS= read -r line || [[ -n "$line" ]]; do
-
content+="$line"$'\n'
-
done
-
printf '%s' "$content" > "$target"
-
-
# Restore read-only if it was read-only before
-
if [[ -n "${restoreReadOnly:-}" ]]; then
-
chmod -w "$target"
-
fi
-
}
-
local f
while IFS= read -r -d $'\0' f; do
isScript "$f" || continue
···
# Preserve times, see: https://github.com/NixOS/nixpkgs/pull/33281
timestamp=$(stat --printf "%y" "$f")
-
sed -e "1 s|.*|#\!$escapedInterpreterLine|" "$f" | _sponge "$f"
+
+
# Manually create temporary file instead of using sed -i
+
# (sed -i on $out/x creates tmpfile /nix/store/x which fails on macos + sandbox)
+
tmpFile=$(mktemp -t patchShebangs.XXXXXXXXXX)
+
sed -e "1 s|.*|#\!$escapedInterpreterLine|" "$f" > "$tmpFile"
+
+
# Make original file writable if it is read-only
+
local restoreReadOnly
+
if [[ ! -w "$f" ]]; then
+
chmod +w "$f"
+
restoreReadOnly=true
+
fi
+
+
# Replace the original file's content with the patched content
+
# (preserving permissions)
+
cat "$tmpFile" > "$f"
+
rm "$tmpFile"
+
if [[ -n "${restoreReadOnly:-}" ]]; then
+
chmod -w "$f"
+
fi
touch --date "$timestamp" "$f"
fi
fi
done < <(find "$@" -type f -perm -0100 -print0)
-
-
unset -f _sponge
}
patchShebangsAuto () {
+39
pkgs/test/stdenv/patch-shebangs.nix
···
// {
meta = { };
};
+
+
preserves-binary-data =
+
(derivation {
+
name = "preserves-binary-data";
+
system = stdenv.buildPlatform.system;
+
builder = "${stdenv.__bootPackages.stdenv.__bootPackages.bashNonInteractive}/bin/bash";
+
initialPath = [
+
stdenv.__bootPackages.stdenv.__bootPackages.coreutils
+
];
+
strictDeps = false;
+
args = [
+
"-c"
+
''
+
set -euo pipefail
+
. ${../../stdenv/generic/setup.sh}
+
. ${../../build-support/setup-hooks/patch-shebangs.sh}
+
mkdir -p $out/bin
+
# Create a script with binary data after the shebang
+
echo "#!/bin/bash" > $out/bin/test
+
echo "echo 'script start'" >> $out/bin/test
+
# Add some binary data (null bytes and other non-printable chars)
+
printf '\x00\x01\x02\xff\xfe' >> $out/bin/test
+
echo >> $out/bin/test
+
echo "echo 'script end'" >> $out/bin/test
+
chmod +x $out/bin/test
+
patchShebangs $out/bin/test
+
# Verify binary data is still present by checking file size and content
+
if ! printf '\x00\x01\x02\xff\xfe' | cmp -s - <(sed -n '3p' $out/bin/test | tr -d '\n'); then
+
echo "Binary data corrupted during patching"
+
exit 1
+
fi
+
''
+
];
+
assertion = "grep '^#!${stdenv.shell}' $out/bin/test > /dev/null";
+
})
+
// {
+
meta = { };
+
};
};
in
stdenv.mkDerivation {
···
read-only-script
preserves-read-only
preserves-timestamp
+
preserves-binary-data
;
};
buildCommand = ''