diff options
| author | tv <tv@krebsco.de> | 2026-11-12 20:25:15 +0000 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-13 03:24:27 +0100 |
| commit | 1880ceb3544de8cf194163394c8291b60924a2e6 (patch) | |
| tree | b932631e5ded3a8a2bf99d8f0e9fb738b9b29453 /lib | |
| parent | 08500cfcbb91cda09c6790b916ba97c333cf2df9 (diff) | |
populate: cope with unusual names and paths
Names and paths with characters that mean something to shells, to find,
or in URLs get handled as what they are, or refused:
- Pruning, and removing state that sources don't need anymore, list
entries with find instead of a loop reading names, which strips blanks
at the ends of names and splits names at newlines. So an entry named
"trail " gets pruned instead of reported as pruned and left.
- Pruning doesn't make entries writable before removing them, which
would change the mode of files elsewhere that are hard links to files
therein.
- Source names are portable file names: letters, digits, and ._-, not
starting with -. nixpkgs' writers accept nothing else in the names of
the scripts populating the sources, which contain the source names, and
fail with an assertion that doesn't mention the source.
- Paths get percent-encoded where they go into URLs for Nix, which
refuses blanks there and takes ? and # for delimiters.
- rsync gets the target path protected from the target's shell
(--protect-args), which expands wildcards in it otherwise: a file source
delivered to /var/src/a?c ends up in /var/src/abc if that exists.
A safety scenario deploys every kind of state to a target path with a
blank, wildcards, #, and %. An edge case prunes entries with blanks at
the ends of their names, with a newline, and with wildcards, and the
scenario pruning links also prunes hard links to a read-only file
outside, and lists what's left in the C locale, where ls sorts .populate
first. The scenario with unusual source names also draws inputs from a
source named self.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/default.nix | 21 |
1 files changed, 21 insertions, 0 deletions
diff --git a/lib/default.nix b/lib/default.nix index 0a99f97..0ffdff2 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -114,6 +114,27 @@ let { in { quote = x: if x == "" then "''" else lib.stringAsChars quoteChar x; + # Shell code defining the function url_path, which prints the path $1 + # as it goes into a URL: with every byte percent-encoded that isn't a + # letter, a digit, or one of -._~/. Nix decodes that, and otherwise + # takes, e.g., ? and # for delimiters, and refuses blanks. + urlPath = /* sh */ '' + url_path() { + printf %s "$1" | od -An -v -tx1 | tr -s ' ' '\n' | + while read -r url_byte; do + case $url_byte in + "") ;; + 2[d-f]|3[0-9]|4[1-9a-f]|5[0-9a]|5f|6[1-9a-f]|7[0-9a]|7e) + printf "\\$(printf %o "0x$url_byte")" + ;; + *) + printf '%%%s' "$url_byte" + ;; + esac + done + } + ''; + # Shell code that enables flakes for the Nix commands following it, and # fails unless Nix supports them, i.e. is version 2.4 or later. `what` # names what needs flakes, for the error message. |
