Skip to content

Fix: chown directories created during caching to PUID/PGID (#178)#180

Merged
Brandon-Haney merged 1 commit into
StudioNirin:mainfrom
Brandon-Haney:fix/issue-178-root-owned-dirs
Jun 5, 2026
Merged

Fix: chown directories created during caching to PUID/PGID (#178)#180
Brandon-Haney merged 1 commit into
StudioNirin:mainfrom
Brandon-Haney:fix/issue-178-root-owned-dirs

Conversation

@Brandon-Haney

Copy link
Copy Markdown
Collaborator

Problem

On Unraid, PlexCache-D creates new top-level library folders (e.g. /mnt/user/data/media/tv-shows/) as root:root with drwxr-xr-x (0755) instead of nobody:users drwxrwxrwx. Because 0755 doesn't grant write access to non-root users, this blocks Sonarr/Radarr from creating new subdirectories inside those folders — imports fail with Access to the path '...' is denied.

Fixes #178.

Root cause

The container runs as root (so it can move files of any ownership) and compensates by chown-ing what it creates to PUID/PGID. File copies already do this via copy_file_with_permissions(), but several move/copy destination directory creations used a raw os.makedirs(), which — running as root — leaves new directories owned by root:root with a umask-derived mode. On a multi-disk array, a /mnt/user0/ write can land the folder chain on a disk where the library root doesn't exist yet, recreating it (and its parents) as root.

Fix

  • Add a shared create_dir_with_ownership() helper in core/system_utils.py that creates a directory tree and chowns every newly created level to PUID/PGID (or the source file's owner when PUID/PGID are unset), best-effort and Linux-only — matching how file copies are already handled.
  • Route the move/copy destination directory creation through it across the caching, eviction, upgrade, restore, symlink, and audit paths.
  • FileUtils.create_directory_with_permissions() now delegates to the helper, so there is a single implementation shared with callers that have no FileUtils instance (the web service layer).

Testing

  • Added TestCreateDirWithOwnership (4 tests): nested-tree creation, no-op when the path already exists, PUID/PGID applied to every newly created level (pre-existing ancestors left untouched), and fallback to the source file's owner when PUID is invalid/unset.
  • Full suite passes.

Manual verification (Unraid, container with PUID=99 / PGID=100)

  1. Trigger a run that moves a watched item back to the array where its show folder doesn't currently exist on the array (or restore a file with no .plexcached backup) — anything that makes PlexCache create a new array folder.
  2. Confirm the newly created library/show/season folders are nobody:users drwxrwxrwx, not root:root drwxr-xr-x.
  3. Confirm Sonarr/Radarr can import a new episode into that folder.

Note: only newly created directories are governed by this change; folders already created as root:root by prior runs are not retroactively fixed (use "Docker Safe New Permissions" once to clean those up).

The container runs as root so it can move files of any ownership, but raw
os.makedirs() then left new array/cache folders owned by root:root (0755).
On Unraid this blocked Sonarr/Radarr from importing into newly created
library folders (StudioNirin#178).

Add a shared create_dir_with_ownership() helper in core/system_utils.py
that chowns every newly created directory level to PUID/PGID (or the
source file's owner when those are unset), the same way file copies are
already handled. Route the move/copy destination directory creation in
the caching, eviction, upgrade, restore, symlink, and audit paths through
it. FileUtils.create_directory_with_permissions now delegates to the
helper so there is a single implementation.
@Brandon-Haney Brandon-Haney merged commit b957f42 into StudioNirin:main Jun 5, 2026
2 checks passed
@Brandon-Haney Brandon-Haney deleted the fix/issue-178-root-owned-dirs branch June 7, 2026 04:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] PlexCache-D creates media library root folders as root:root on Unraid, breaking Sonarr/Radarr imports

2 participants