fix(storage): unlink dir symlinks without deleting targets - #53447
fix(storage): unlink dir symlinks without deleting targets#53447fxprunayre wants to merge 3 commits into
Conversation
36ca73a to
9fb276c
Compare
|
Hello there, We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process. Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6 Thank you for contributing to Nextcloud and we hope to hear from you soon! (If you believe you should not receive this message, you can add yourself to the blocklist.) |
Nextcloud allow following symlink (https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/config_sample_php_parameters.html#localstorage-allowsymlinks) but removal of symlink remove files in the target of the symlink and fail to remove the link returning an error. Using the following structure: ``` . ├── afolder │ └── test.txt ├── alink -> afolder └── welcome.txt ``` created with: ```bash mkdir afolder touch afolder/test.txt ln -s afolder alink ``` After deletion of `alink` symbolic link, the content of `afolder` is removed, the link also and an error is reported. ```json { "method":"DELETE", "url":"/remote.php/dav/files/admin/alink", "message":"rmdir(/data/dev/nextcloud/data/admin/files/alink): Not a directory at /data/dev/nextcloud/lib/private/Files/Storage/Local.php#128" } ``` Results is: ``` . ├── afolder └── welcome.txt ``` If the resource to be deleted is a link, unlink it (and preserve link target content). ``` . ├── afolder │ └── test.txt └── welcome.txt ``` Signed-off-by: Francois Prunayre <fx.prunayre@gmail.com>
9fb276c to
63ebd2b
Compare
Resolve the source path once, clear the stat cache before checking whether it is a symlink, and use an early return to avoid nesting the recursive directory removal logic. Signed-off-by: Josh <josh.t.richards@gmail.com>
Verify that deleting a directory symlink through rmdir or unlink removes only the link while preserving the target directory and its contents. Assisted-by: Copilot:gpt-5.6-sol Signed-off-by: Josh <josh.t.richards@gmail.com>
joshtrichards
left a comment
There was a problem hiding this comment.
Makes sense. Sorry about taking so long to review!
I took the liberty of:
- moving the clearstatcache() before the is_link() call
- refactoring slightly for clarity
- adding unit tests
|
/backport to stable35 |
|
/backport to stable34 |
1 similar comment
|
/backport to stable34 |
|
/backport to stable33 |
|
/backport to stable32 |
Summary
Nextcloud supports following symbolic links when
localstorage.allowsymlinksis enabled. However, deleting a symbolic link to a directory recursively deleted the contents of the target directory before failing to remove the link itself.This change detects when the path passed to local storage directory removal is a symbolic link and unlinks it directly, preserving the target directory and its contents.
Before
Given:
Created with:
Deleting
alinkrecursively removedafolder/test.txtand then reported an error:{ "method": "DELETE", "url": "/remote.php/dav/files/admin/alink", "message": "rmdir(/data/dev/nextcloud/data/admin/files/alink): Not a directory" }The resulting structure was:
After
Deleting
alinknow removes only the symbolic link. The link target and its contents are preserved:Implementation
Local::rmdir().Added parameterized regression coverage in
LocalTest.phpfor deletion through both storage entry points:Local::rmdir()Local::unlink()The tests verify that:
Todo
Quite new to the Nextcloud codebase, any pointer to a test related to symlink is welcomed.
Checklist