librelad 2d24a764a8 refactor(storage): route elevation tests and the WebUI tree through paths.sh
Two mechanical sweeps, no behaviour change on a single-root install.

The 14 `[[ "$p" == "$containers_dir"* ]]` prefix tests that decide
manager-vs-container-user elevation become pathIsContainerData, so a file
on a second storage root is no longer misclassified as manager-owned —
which would have written it with the wrong owner and failed later, far
from the cause. The 65 references to the WebUI's own tree become
webuiDir(), which is pinned to the primary root by design.

Two traps found while doing it:

run_privileged.sh is sourced directly by init.sh without paths.sh, so it
needs a fallback. Defining one named pathIsContainerData was wrong:
generate_function_manifest.sh indexes top-level definitions, and the
resulting autoload stub would have shadowed the real multi-root
implementation with the primary-only fallback — silently classifying
every file on a second disk as manager-owned, which is exactly the bug
this sweep exists to prevent. Renamed to _runCfgIsContainerPath, which
delegates when the real one is loaded.

setup_lock.sh built its path in a top-level assignment, so it was
evaluated at source time and needed the file flagged eager. Made it a
function instead: the path resolves on call, and the file drops off
LP_EAGER_FILES entirely.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 04:04:19 +01:00

67 lines
2.3 KiB
Bash
Executable File

#!/bin/bash
copyFile()
{
local silent_flag="$1"
local file="$2"
local file_name=$(basename "$file")
local save_dir="$3"
local save_dir_file=$(basename "$save_dir")
local user_name="$4" # advisory — the destination path determines the owner
local flags="$5"
local flags_full=""
[[ "$flags" == "overwrite" ]] && flags_full="-f"
# Write as the destination's owner — no root, no chown. Under
# /docker/containers/<app> that's the docker install user (runFileOp);
# the manager-owned control plane (configs/logs/etc.) is runInstallOp.
# Mirrors createTouch's path-based ownership; $user_name is now advisory.
local op="runInstallOp"
pathIsContainerData "$save_dir" && op="runFileOp"
if [ "$silent_flag" == "loud" ]; then
local result; result=$($op cp $flags_full "$file" "$save_dir")
checkSuccess "Copying $file_name to $save_dir_file"
else
$op cp $flags_full "$file" "$save_dir" >/dev/null 2>&1
fi
}
# Docker materialises a missing bind-mount source as an empty DIRECTORY when the
# container starts. Where the mount is a FILE (an app's <app>.config), that
# directory is self-perpetuating: tar extraction fails with "Cannot open: File
# exists", `cp` drops the real file INSIDE it, `-e`/`-r` checks still pass, and
# the container reads a directory (EISDIR) and exits on boot.
# Restore the regular file: promote a same-named file from inside the stub if the
# copy already landed there, then drop the stub. Returns non-zero if the path is
# still a directory afterwards.
repairStubDirForFile()
{
local target="$1"
local silent_flag="${2:-silent}"
[[ -d "$target" ]] || return 0
local op="runInstallOp"
pathIsContainerData "$target" && op="runFileOp"
local name; name=$(basename "$target")
local staged="$target.stub-repair.$$"
if [[ -f "$target/$name" ]]; then
$op cp -f "$target/$name" "$staged" >/dev/null 2>&1
$op rm -rf "$target" >/dev/null 2>&1
$op mv "$staged" "$target" >/dev/null 2>&1
else
$op rm -rf "$target" >/dev/null 2>&1
fi
if [[ -d "$target" ]]; then
isNotice "Could not repair '$target' — it is a directory where a file is required."
return 1
fi
[[ "$silent_flag" == "loud" ]] && isNotice "Repaired '$name' (Docker had created it as a bind-mount directory)."
return 0
}