From 172beca3c5a4430653609c2a6b59775afabe693d Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Tue, 25 Aug 2026 18:29:43 -0400 Subject: [PATCH] =?UTF-8?q?A=20state=20key=20is=20a=20file=20path,=20not?= =?UTF-8?q?=20a=20regex=20=E2=80=94=20a=20release=20tag=20like=20[Bluray-1?= =?UTF-8?q?080p]=20holds=20an=20invalid=20range,=20so=20grep=20bailed=20an?= =?UTF-8?q?d=20the=20tempfile=20swap=20wiped=20every=20other=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common.sh | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/common.sh b/common.sh index 6ca91ba..98fb10d 100755 --- a/common.sh +++ b/common.sh @@ -2273,8 +2273,10 @@ acquire_rsync_lock() { # ============================================================================================== # Generic get/set for flat "keyvalue" state files (one entry per line) — the pattern # every watchdog's strike-tracking and state-file logic was independently reimplementing. -# grep -v + tempfile-swap on write, not sed -i in place — avoids sed treating a key containing -# regex metacharacters (container names, etc.) as part of the substitution pattern. +# Keys are matched as literal prefixes via awk substr(), never as regexes. A key is often a +# media file path, and a release tag like [Bluray-1080p] is a valid-looking bracket expression +# holding the reversed range 1-0 — grep -E rejects it, exits 2, and the tempfile-swap then +# commits an empty file, silently wiping every other entry. # # Usage: wd_state_get "$key" "$file" [sep=:] # wd_state_set "$key" "$value" "$file" [sep=:] @@ -2284,14 +2286,24 @@ acquire_rsync_lock() { # keep their own thin same-named wrapper around these rather than changing call sites. wd_state_get() { local key="$1" file="$2" sep="${3:-:}" - grep -E "^${key}${sep}" "$file" 2>/dev/null | cut -d"$sep" -f2- + [[ -f "$file" ]] || return 0 + awk -v pfx="${key}${sep}" \ + 'substr($0, 1, length(pfx)) == pfx { print substr($0, length(pfx) + 1); exit }' \ + "$file" 2>/dev/null } +# Returns 1 without touching the state file if the rewrite fails, so a read error costs the +# caller one update rather than the whole file. wd_state_set() { local key="$1" value="$2" file="$3" sep="${4:-:}" - grep -vE "^${key}${sep}" "$file" 2>/dev/null > "${file}.tmp" - echo "${key}${sep}${value}" >> "${file}.tmp" - mv "${file}.tmp" "$file" + local tmp="${file}.tmp" + : > "$tmp" || return 1 + if [[ -f "$file" ]]; then + awk -v pfx="${key}${sep}" \ + 'substr($0, 1, length(pfx)) != pfx' "$file" > "$tmp" || { rm -f "$tmp"; return 1; } + fi + echo "${key}${sep}${value}" >> "$tmp" + mv "$tmp" "$file" } # ==============================================================================================