Gate arr orphan deletion on ctime and stop the nightly permissions pass from restamping it — imports preserve the release's original mtime, so the age gate never actually fired for real content

This commit is contained in:
Gmer4Lfe
2026-07-27 18:38:18 -04:00
parent 3084546b32
commit d680bd0549
5 changed files with 80 additions and 23 deletions
+25 -5
View File
@@ -40,6 +40,9 @@
# Empty array guard — warns and exits cleanly if no shares configured
# Folder existence — skips missing shares with warning, continues others
# Separate passes — directories and files chmod'd separately for correctness
# Conditional passes — only entries whose owner/mode is actually wrong are touched.
# chown/chmod restamp ctime even when the value doesn't change,
# and the arr cleanups gate orphan deletion on ctime
# platform_require_cmd — notify script validated before use
# Silent by default — only failures produce output, success is silent
#
@@ -143,6 +146,10 @@ SKIPPED=()
TOTAL_DIRS_FIXED=0
TOTAL_FILES_FIXED=0
# Split for find's -user/-group predicates, which take them separately
PERMISSIONS_USER="${PERMISSIONS_OWNER%%:*}"
PERMISSIONS_GROUP="${PERMISSIONS_OWNER##*:}"
for SHARE in "${MEDIA_PERMISSION_SHARES[@]}"; do
SHARE_NAME=$(basename "$SHARE")
@@ -158,7 +165,7 @@ for SHARE in "${MEDIA_PERMISSION_SHARES[@]}"; do
2>/dev/null | wc -l)
FILE_COUNT=$(find "$SHARE" -type f ! -perm "${PERMISSIONS_FILE_MODE:-664}" \
2>/dev/null | wc -l)
OWNER_COUNT=$(find "$SHARE" ! -user nobody -o ! -group users \
OWNER_COUNT=$(find "$SHARE" \( ! -user "$PERMISSIONS_USER" -o ! -group "$PERMISSIONS_GROUP" \) \
2>/dev/null | wc -l)
warn "DRY RUN — $SHARE_NAME: $DIR_COUNT dirs, $FILE_COUNT files, $OWNER_COUNT ownership fixes needed"
continue
@@ -170,21 +177,34 @@ for SHARE in "${MEDIA_PERMISSION_SHARES[@]}"; do
CHMOD_FILE_OK=true
CHOWN_OK=true
# Every pass below is conditional — it touches only entries that are actually wrong.
# This is not just an optimisation. chown/chmod rewrite an inode's ctime even when the
# value is unchanged, so a blanket pass restamps every file in the share each night and
# erases ctime as an age signal. The arr cleanups need that signal to tell a file that
# just landed from one that has sat untracked for days — mtime can't do it, because an
# import preserves the release's original timestamp (measured 2026-07-27: 400 of 400
# files imported that week had mtimes over 7 days old, one of them 9613 days).
# Count files with wrong ownership before fixing (diagnostic)
WRONG_OWNER=$(find "$SHARE" \( ! -user nobody -o ! -group users \) \
WRONG_OWNER=$(find "$SHARE" \( ! -user "$PERMISSIONS_USER" -o ! -group "$PERMISSIONS_GROUP" \) \
2>/dev/null | wc -l)
# Apply ownership first — affects all files and directories
chown -R "$PERMISSIONS_OWNER" "$SHARE" 2>/dev/null || CHOWN_OK=false
if [[ "$WRONG_OWNER" -gt 0 ]]; then
find "$SHARE" \( ! -user "$PERMISSIONS_USER" -o ! -group "$PERMISSIONS_GROUP" \) \
-exec chown "$PERMISSIONS_OWNER" {} + 2>/dev/null || CHOWN_OK=false
fi
# Apply directory permissions — separate pass for correctness
# Directories need execute bit — different from files
find "$SHARE" -type d -exec chmod "${PERMISSIONS_DIR_MODE:-755}" {} + \
find "$SHARE" -type d ! -perm "${PERMISSIONS_DIR_MODE:-755}" \
-exec chmod "${PERMISSIONS_DIR_MODE:-755}" {} + \
2>/dev/null || CHMOD_DIR_OK=false
# Apply file permissions — no execute bit on media files
# Ignore "No such file" errors: race condition with volatile dirs (e.g. Emby transcodes)
_chmod_errs=$(find "$SHARE" -type f -exec chmod "${PERMISSIONS_FILE_MODE:-664}" {} + 2>&1 | \
_chmod_errs=$(find "$SHARE" -type f ! -perm "${PERMISSIONS_FILE_MODE:-664}" \
-exec chmod "${PERMISSIONS_FILE_MODE:-664}" {} + 2>&1 | \
grep -v "No such file or directory" | grep -c "chmod:" || true)
[[ "$_chmod_errs" -gt 0 ]] && CHMOD_FILE_OK=false