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" } # ==============================================================================================