Re-shared external storage (SMB) not always rescanned for recipients
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 36.9k
- Forks
- 5.2k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 713
Description
Steps to reproduce
- User A adds an SMB external storage mount.
- User A shares a folder from that mount directly with User B.
- Something changes on the SMB server outside of Nextcloud.
- User A browses the folder → gets rescanned correctly.
- User B browses the re-share → does not get rescanned (stale listing).
Root cause
SharedStorage::getWatcher() decides between a real Watcher and a
NullWatcher purely from string metadata on the share's cache entry:
https://github.com/nextcloud/server/blob/master/apps/files_sharing/lib/SharedStorage.php#L453-L477
$node = $this->getShare()->getNodeCacheEntry();
if ($node instanceof CacheEntry) {
$storageId = $node->getData()['storage_string_id'] ?? null;
if ($storageId !== null && !(str_starts_with($storageId, 'home::') || str_starts_with($storageId, 'object::user'))) {
// real watcher, rescans happen
}
}
// falls through here -> NullWatcher, rescans never happen
$this->watcher = new NullWatcher();
getNodeCacheEntry() returns null, or a CacheEntry missing the
storage_string_id key, for several legitimate code paths:
DefaultShareProvider::getSharesBy()/getShareById()/getSharesByPath()
never populate a node cache entry at all (nofilecache/storagesjoin).- Even
DefaultShareProvider::_getSharedWith()(used for the normal
getMountsForUser/getMountsForPathmount setup) can come back without
storage_string_idif the source node wasn't infilecacheyet at
share-fetch time.
Whenever that happens, the code silently assumes "home storage" and installs
a NullWatcher, meaning the share never gets checked against the real
backend for the lifetime of that storage object/request.
This is the same fragile spot as #50235, which was patched defensively in
#50769 (?? null to avoid the crash) — that fixed the exception but left the
underlying "silently never rescan" behavior in place.
Suggested fix
Fall back to a live, deterministic check of the real underlying storage
($this->nonMaskedStorage->instanceOfStorage(IHomeStorage::class), after
$this->init()) when the cache-entry metadata is missing or incomplete,
instead of assuming home storage. This mirrors the existing fallback pattern
in SharedStorage::getSourceRootInfo(). A FailedStorage guard is needed so
a deleted owner / offline storage still safely yields NullWatcher.
I'm happy to submit a PR for this if the approach sounds right.
This issue has been created in cooperation with Claude Sonnet 5 but it has been reviewed and submitted by me - human.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/files_sharing/lib/SharedStorage.php at getWatcher(), then compare its metadata path with the fallback pattern in getSourceRootInfo(). Trace initialization of nonMaskedStorage and the FailedStorage case, and verify the behavior when storage_string_id is absent. Done means a re-shared SMB folder is rescanned for recipients while deleted or unavailable owner storage still uses NullWatcher safely.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- backend, cloud
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100