Skip to content

fix(cmd,csync): anchor --exclude patterns at the sync root regardless of filename#10284

Open
mosandlt wants to merge 1 commit into
nextcloud:masterfrom
mosandlt:fix-exclude-cli-anchor-basepath
Open

fix(cmd,csync): anchor --exclude patterns at the sync root regardless of filename#10284
mosandlt wants to merge 1 commit into
nextcloud:masterfrom
mosandlt:fix-exclude-cli-anchor-basepath

Conversation

@mosandlt

@mosandlt mosandlt commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

nextcloudcmd --exclude <path> silently produced zero exclusions for every pattern in the file, unless <path> happened to be literally named sync-exclude.lst — with no warning or error anywhere. Any other filename (a typo'd extension, a descriptive name, a per-tool name like myapp-exclude.lst) caused every single pattern to be matched against the wrong base directory, so none of them ever excluded anything under the sync root.

Root cause

ExcludedFiles::addExcludeFilePath() in src/csync/csync_exclude.cpp anchors patterns either at the sync root (_localPath) or at the exclude file's own containing directory, based on a filename check: literally sync-exclude.lst → sync root, anything else → own directory.

That heuristic was introduced in 5788f35 (2020-12-09, "Skip sync exclude file from list of exclude files if it doesn't exist") to merge two previously-separate code paths: the GUI's global exclude list (always named sync-exclude.lst, lives outside any sync folder, needs sync-root anchoring) and a per-directory .sync-exclude.lst discovered during traversal (needs anchoring at its own directory). It was a side effect of that merge, not a deliberate choice — the commit's own description and linked issue are unrelated to anchoring behavior.

src/cmd/cmd.cpp passes the CLI's --exclude value into the same function unconditionally, so it inherited this GUI-specific heuristic even though CLI users can name their exclude file anything.

Reported independently by multiple users, never properly root-caused:

Fix

Add an explicit anchorToLocalPath parameter to addExcludeFilePath() (default false, preserving current behavior everywhere else) and set it for the CLI's --exclude option in cmd.cpp, so its patterns are always anchored at the sync root regardless of the file's name.

Test plan

  • New unit test: testAddExcludeFilePath_anchorToLocalPath_bypassesFilenameHeuristic
  • Full ExcludedFilesTest suite: 25 passed, 0 failed
  • Manual repro against a live Nextcloud account: an --exclude file not named sync-exclude.lst previously had zero effect (excluded directories were downloaded anyway); after this fix they are correctly skipped (FileIgnored) with no behavior change for GUI-managed exclude lists

Checklist

AI (if applicable)

@mosandlt mosandlt force-pushed the fix-exclude-cli-anchor-basepath branch from 46bca62 to 770e9e8 Compare July 2, 2026 04:46

@mgallien mgallien left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice idea
please have a look at my comments and let me know if things are not clear

Comment thread src/csync/csync_exclude.cpp Outdated
Comment thread src/csync/csync_exclude.h Outdated
Comment thread test/testexcludedfiles.cpp Outdated
@mgallien

mgallien commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

the PR description is missing some parts that are in the template including things relevant for our AI policy
can you add this back:

Checklist

AI (if applicable)

@mosandlt mosandlt force-pushed the fix-exclude-cli-anchor-basepath branch from 770e9e8 to 1e0a8af Compare July 2, 2026 10:12
@mosandlt

mosandlt commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Added the checklist back, including the AI disclosure section and an Assisted-by: ClaudeCode:claude-sonnet-5 trailer on the commit (force-pushed). Let me know if anything else is missing.

@mgallien

mgallien commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Added the checklist back, including the AI disclosure section and an Assisted-by: ClaudeCode:claude-sonnet-5 trailer on the commit (force-pushed). Let me know if anything else is missing.

thanks for the quick reply
please also have a look at my review comments on the code itself

@mosandlt mosandlt force-pushed the fix-exclude-cli-anchor-basepath branch from 1e0a8af to e5db10e Compare July 2, 2026 17:44
@mosandlt

mosandlt commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Addressed all three review comments:

  • Replaced the bool anchorToLocalPath param with a scoped ExcludedFiles::ExcludeFileAnchor enum (FileDirectory / SyncRoot) for readability at call sites.
  • Kept the doc comment on addExcludeFilePath() in csync_exclude.h, updated for the enum.
  • Trimmed the redundant issue-reference comment in the test file (context is in the commit message).

Also rebased onto current master to pick up #10283 (which landed the missing---exclude-file fatal-error check) and merged that with this fix's sync-root anchoring in cmd.cpp. Force-pushed.

… of filename

Summary
nextcloudcmd --exclude <path> silently produced zero exclusions for
every pattern in the file, unless <path> happened to be literally
named "sync-exclude.lst" -- with no warning or error anywhere. Any
other filename (a typo'd extension, a descriptive name, a per-tool
name like myapp-exclude.lst) caused every single pattern to be
matched against the wrong base directory, so none of them ever
excluded anything under the sync root.

Root cause
ExcludedFiles::addExcludeFilePath() in src/csync/csync_exclude.cpp
anchors patterns either at the sync root (_localPath) or at the
exclude file's own containing directory, based on a filename check:
literally "sync-exclude.lst" -> sync root, anything else -> own
directory. That heuristic was introduced in 5788f35 (2020-12-09,
"Skip sync exclude file from list of exclude files if it doesn't
exist") to merge two previously-separate code paths: the GUI's
global exclude list (always named sync-exclude.lst, lives outside
any sync folder, needs sync-root anchoring) and a per-directory
.sync-exclude.lst discovered during traversal (needs anchoring at
its own directory). It was a side effect of that merge, not a
deliberate choice -- the commit's own description and linked issue
are unrelated to anchoring behavior.

src/cmd/cmd.cpp passes the CLI's --exclude value into the same
function unconditionally, so it inherited this GUI-specific
heuristic even though CLI users can name their exclude file
anything. Reported independently by multiple users:
nextcloud#2916, nextcloud#7682, and a comment
diagnosing the exact same filename dependency on nextcloud#2916.

Fix
Add an explicit anchorToLocalPath parameter to addExcludeFilePath()
(default false, preserving current behavior everywhere else) and set
it for the CLI's --exclude option in cmd.cpp, so its patterns are
always anchored at the sync root regardless of the file's name.

Test plan
- [x] New unit test:
      testAddExcludeFilePath_anchorToLocalPath_bypassesFilenameHeuristic
- [x] Full ExcludedFilesTest suite: 25 passed, 0 failed
- [x] Manual repro against a live Nextcloud account: an --exclude file
      not named sync-exclude.lst previously had zero effect (excluded
      directories were downloaded anyway); after this fix they are
      correctly skipped (FileIgnored) with no behavior change for
      GUI-managed exclude lists.

Signed-off-by: Thomas Mosandl <[email protected]>
Assisted-by: ClaudeCode:claude-sonnet-5
@mosandlt mosandlt force-pushed the fix-exclude-cli-anchor-basepath branch from e5db10e to a52f79a Compare July 4, 2026 19:05
@mosandlt

mosandlt commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current master. Also just double-checked against your 3 review comments — all already addressed in the current HEAD (the fixes must have landed after your review, before you could see the update):

  • csync_exclude.cpp: parameter is now an enum class (ExcludeFileAnchor::FileDirectory / SyncRoot) instead of a bool
  • csync_exclude.h: addExcludeFilePath() now has a full doc comment explaining the anchoring heuristic and when to use SyncRoot
  • testexcludedfiles.cpp: trimmed the test comment down to 3 lines describing only what the test does, moved the issue-number/root-cause context to the commit message where it already lived

Let me know if anything still needs another pass.

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.

3 participants