Skip to content

Fix/57375 zero quota external storage folder delete#59986

Open
huntervcx wants to merge 1 commit into
nextcloud:masterfrom
DYB-Corp:fix/57375-zero-quota-external-storage-folder-delete
Open

Fix/57375 zero quota external storage folder delete#59986
huntervcx wants to merge 1 commit into
nextcloud:masterfrom
DYB-Corp:fix/57375-zero-quota-external-storage-folder-delete

Conversation

@huntervcx
Copy link
Copy Markdown

@huntervcx huntervcx commented Apr 28, 2026

Summary

Users with quota set to 0 (intentionally, so nothing is stored under their home files/ except structure / external mounts) hit incorrect WebDAV failures:

  1. MKCOL / uploads / moves could fail with 507 Insufficient Storage because QuotaPlugin treated directory creation like a fixed byte write (4096) against free_space == 0, and the home Quota wrapper blocked mkdir when quota was exhausted.

  2. With files_trashbin enabled, DELETE on items on external storage could return 403 Forbidden (Directory::deletermdir false) because Quota::copyFromStorage / related write paths did not honor shouldApplyQuota() — writes under files_trashbin/ were incorrectly subject to the same free_space == 0 gate as real user files under files/.

This PR aligns quota enforcement with the existing intent of shouldApplyQuota() (only paths under files/ count toward user quota):

  • QuotaPlugin: skip pre-quota checks for directory creation (MKCOL); empty dirs do not consume user quota bytes.
  • Quota wrapper: allow mkdir when quota is exactly 0 for empty directories; delegate real file blocking to fopen / file_put_contents / etc.
  • Quota wrapper: apply shouldApplyQuota() to copyFromStorage, moveFromStorage, copy, file_put_contents, and touch so trashbin / versions / metadata paths are not blocked when home quota is 0.

Unit tests updated in tests/lib/Files/Storage/Wrapper/QuotaTest.php and apps/dav/tests/unit/Connector/Sabre/QuotaPluginTest.php.

TODO

  • CI green

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

@huntervcx huntervcx marked this pull request as ready for review April 28, 2026 19:49
@huntervcx huntervcx requested a review from a team as a code owner April 28, 2026 19:49
@huntervcx huntervcx requested review from ArtificialOwl, come-nc, provokateurin and sorbaugh and removed request for a team April 28, 2026 19:49
@huntervcx
Copy link
Copy Markdown
Author

Behavior Matrix After Full Fix

Scenario (quota = 0) Before After
MKCOL in home / SMB 507 / 403 OK (fix 1)
PUT in files/ 507 507 (correct)
PUT in external SMB OK OK
DELETE → trashbin (copyFromStorage) 403 Forbidden 204 No Content
Versions (files_versions) blocked OK
Touch in files/ blocked blocked (correct)
Touch elsewhere blocked OK

I'm still not entirely certain whether the behavior for trashbin and versions is fully aligned with the intended design.

That said, with this fix, it is now possible to create directories in the user's home even when the quota is set to 0. From Nextcloud’s perspective, this is technically consistent, as empty directories do not consume any storage (0 bytes), and therefore do not violate the quota constraint.

@huntervcx huntervcx force-pushed the fix/57375-zero-quota-external-storage-folder-delete branch from 8a910a1 to e4ce8ad Compare April 28, 2026 20:01
Comment on lines +242 to +252
// Creating an empty directory (MKCOL) does not consume user quota bytes:
// it is only a cache / metadata entry. Leave the final decision to the
// target storage (the Quota wrapper is only attached to the home storage
// and can still refuse if needed; external mounts have no quota wrapper).
// Without this short-circuit, a user whose quota is intentionally set to 0
// (so that all content lives on external mounts) cannot create folders at
// all, including paths that actually resolve to an external mount.
if ($isDir) {
return true;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If I remember correctly this is not an acceptable behaviour, because it means a user with 0 quota can fill your storage space by creating empty directories, which still use up disk space.

@github-actions
Copy link
Copy Markdown
Contributor

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

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.)

When the user quota is exhausted (notably quota=0), writes to metadata
locations like files_trashbin/ and files_versions/ were incorrectly
gated on free_space == 0 the same way as real files under files/.

The most visible symptom is on DELETE of an item on an external mount
when files_trashbin is enabled: the move-to-trash copy lands in
files_trashbin/ which has no quota meaning, yet Quota::copyFromStorage
refused it because the home free_space is 0. DAV then returned HTTP 403.

Honor shouldApplyQuota() in the remaining write paths so the existing
"only files/ counts against user quota" intent is consistent across all
of them: file_put_contents, copy, copyFromStorage, moveFromStorage,
touch and writeStream. mkdir is left as-is because empty directories
still consume disk inodes and must not be allowed on the home when the
quota is 0 (would otherwise let a user fill the underlying disk).

Signed-off-by: Arthur Perrot <aperrot@dyb.fr>
@huntervcx huntervcx force-pushed the fix/57375-zero-quota-external-storage-folder-delete branch from e4ce8ad to 9643b08 Compare May 16, 2026 13:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Users With 0B Quota Cannot Delete Folders In External Storage

2 participants