Skip to content

[Bug] A single desynced filecache path makes an entire group folder directory return 500 #61649

Description

@pringelmann

Description

When a folder is moved between two team folders that share one object-store storage, and the moved folder is reachable through a nested cache jail (it was also shared to a user who already has access via the team folder, a "double share"), the move updates the folder's own oc_filecache row but not its children. The children keep the source jail's path prefix.

After that, opening the destination folder returns HTTP 500 for everyone. View::getDirectoryContent() maps each child through $storage->getOwner($child->getPath()), the desynced child resolves to a null path, and getOwner(null) throws a TypeError that aborts the whole PROPFIND. One bad entry makes the entire directory unreadable.

The corruption source is already fixed by #59252 / #53934. But that fix is preventive only: instances corrupted before it stay broken.

Steps to reproduce

On a build with #59252 reverted, primary S3 object store, groupfolders with shared storage:

  1. Create two team folders, TeamA and TeamB, both on the same object store (so they are jails inside one storage).
  2. As a member, create TeamA/Sub with a couple of files.
  3. Share TeamA/Sub with a second user who is also a member of TeamA (the "double share" stacks a share cache jail on the team-folder jail).
  4. As that second user, move Sub out of the share into TeamB.
  5. Open TeamB/Sub. -> 500.

oc_filecache then shows the moved folder under __groupfolders/<TeamB>/… while its children still read __groupfolders/<TeamA>/…. Upgrading past #59252 does not repair these rows, and opening the folder still 500s (confirmed on a patched 32.0.10).

Why I think it happens

CacheJail::getMoveInfo() returned getSourcePath($path) (relative to the inner jail) instead of getUnjailedSourcePath($path) (relative to the base storage). With nested jails the two diverge, so the cache move rewrote the folder row but not its descendants.

Separately, View::getDirectoryContent() calls getOwner() per child with no null guard, so any single unresolvable path throws TypeError: getOwner(): Argument #1 ($path) must be of type string, null given and kills the entire listing instead of just that one entry.

Possible fix

  • getDirectoryContent() should skip and log entries whose path can't be resolved, rather than 500 the whole directory on one bad row.
  • an occ command to find and fix descendant rows whose path prefix doesn't match their parent's jail, for instances corrupted before the fix.

Reproduced on 32.0.10 with #59252 reverted; residual 500 confirmed with #59252 in place.

Metadata

Metadata

Assignees

No one assigned

    Type

    No fields configured for Bug.

    Projects

    Status
    To triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions