Recycle Bin & Trash Subsystem¶
This document specifies the DVFS deletion architecture, broken down into its safety principles (In Essence) and its internal mechanics (Implementation Quirks).
1. In Essence: Two-Tier Deletion Safety¶
Distributed filesystems require protection against accidental user deletions. DVFS provides a two-tier deletion lifecycle:
[Active File]
|
+---> trash <name> ---> [Soft-Deleted in .trash/] ---> restore <name> ---> [Restored File]
| |
| +---> delete -t <name> / clear_trash ---> [Permanently Destroyed]
|
+---> delete <name> ---> [Permanently Destroyed]
- Soft Delete (
trash): Moves the file or directory into a protected, hidden.trash/container. The item is removed from active directory listings but its data and permissions remain intact on disk, allowing near-instant restoration. - Permanent Delete (
delete): Executes a recursive depth-first search (DFS) post-order purge from the FileServer, unlinks inodes from memory and persistent stores, removes physical OS files, and broadcasts unsharing notices. - Trash Isolation Invariant: The
.trash/container is strictly protected. Users cannot navigate into.trash/withcd, nor can they create new files directly inside.trash/.
2. Implementation Quirks & Practical Realities¶
2.1 The Physical .trash/ Directory¶
Each user root on a FileServer maintains a dedicated .trash/ folder:
- Automatic Initialization: Created automatically on user creation or first trash operation.
- Reserved Name: The name .trash is reserved by the FileServer. Any attempt to create a file or folder named .trash via create or mkdir is rejected with an error.
- Physical Relocation: Trashing uses os.Rename to move the physical file or directory on the host filesystem into .trash/. Subtree paths and internal inode parent pointers are updated in memory, and the persistent InodeStore is updated via RenamePrefix to reflect the path changes.
2.2 Collision-Safe Renaming in Trash¶
If a user trashes a file named report.pdf from mydrive/docs/, and later trashes another file named report.pdf from mydrive/downloads/, storing both in .trash/ would cause an OS collision.
The FileServer resolves this with uniqueNameInDirLocked:
- If report.pdf does not exist in .trash/, it is moved as report.pdf.
- If a collision occurs, the FileServer appends the inode ID: report.pdf__42.
- When restored, the collision suffix is stripped, restoring the original name.
2.3 Restore Metadata & Fallback Rules¶
When an item is moved to trash, the FileServer records its restoration context in an in-memory table named fs.trashMeta:
type trashEntry struct {
originalParentFID string
originalName string
originalRelPath string
sharedSnapshots []sharedDirSnapshot
}
- Standard Restoration: When
restore <name>is executed, the FileServer looks upfs.trashMeta, identifies the original parent directory FID, and re-attaches the inode to its original parent. - Parent Deletion Fallback: If the original parent directory was deleted while the file was in trash, but the metadata is present, the FileServer gracefully falls back to restoring the item directly into the user's root directory (
mydrive). - Restart Limitation: Because
fs.trashMetais stored in-memory, if the FileServer process restarts while items remain in trash, attempting to restore them returns:"restore metadata not available (try restoring before restarting the server)". Users should restore required files prior to planned FileServer maintenance restarts.
2.4 Shared-User Trash Scoping¶
When multiple users collaborate inside a shared directory:
- Shared users can move files they have permission to modify into trash.
- However, when a shared user runs show_trash, the FileServer filters the entries using userCanAccessInode. A shared user only sees trashed items that were shared with them, and cannot see or restore the owner's private trashed files.
- Restoring is also strictly ACL-checked; a user cannot restore files from .trash/ that they do not have permissions to access.
2.5 Complete CLI Deletion Reference¶
| Command | Flags | Target | Behavior |
|---|---|---|---|
trash <name> |
-r (recursive) |
Active Directory | Soft delete: moves file or directory to .trash/. Non-empty directories require -r. |
restore <name> |
None | Trash Directory | Restores specified item from .trash/ back to its original directory. |
show_trash |
None | Trash Directory | Lists all items currently in .trash/ without requiring directory navigation. |
clear_trash |
None | Trash Directory | Permanently deletes all items currently in .trash/. |
delete <name> |
-r (recursive) |
Active Directory | Permanent hard delete: bypasses trash and destroys file/directory immediately. |
delete -t <name> |
-t (from trash) |
Trash Directory | Permanently purges a specific item from .trash/ without clearing other trashed files. |
3. Manual Trash & Restore Test Runbook¶
Follow these 9 scenarios inside the client REPL to verify all trash and restore invariants:
Case 1: Basic File Trash & Restore¶
Expected:doc.txt is removed from test_trash/.
Expected: doc.txt appears in .trash/ listing.
Expected: doc.txt is successfully restored back into test_trash/.
Case 2: Non-Empty Directory Trash Requires -r¶
Expected: Fails with error: directory is not empty; use -r to trash recursively.
Expected: Succeeded; myfolder is moved to trash.
Case 3: Direct Permanent Delete¶
Expected:perm_dir is permanently purged; it does NOT appear in show_trash.
Case 4: Collision-Safe Renaming in .trash/¶
mkdir dirA dirB
cd dirA
create report.txt
cd ../dirB
create report.txt
cd ../dirA
trash report.txt
cd ../dirB
trash report.txt
show_trash
report.txt) and one with its inode ID disambiguator (report.txt__<inodeID>).
Case 5: Protection of .trash/ Namespace¶
Expected: FileServer rejects creation of items named .trash. Direct navigation (cd .trash) is likewise rejected.
Case 6: Emptying Trash (clear_trash)¶
Expected: All trashed items are permanently unlinked; show_trash outputs (trash is empty).
Case 7: Selective Item Deletion from Trash (delete -t)¶
create fileA.txt
create fileB.txt
trash fileA.txt
trash fileB.txt
show_trash
delete -t fileA.txt
show_trash
fileA.txt is permanently purged; fileB.txt remains intact in .trash/.
Case 8: Server Restart Limitation Verification¶
create test_restart.txt
trash test_restart.txt
show_trash
# In FileServer terminal, restart the fileserver process
# Back in client:
refresh
restore test_restart.txt
restore metadata not available (try restoring before restarting the server).
Case 9: Shared-User Trash Scoping & ACL Isolation¶
- User
aliceshares folderprojwith userbob. alicetrashes a private filesecret.txtinmydrive.bobtrashestask.txtinsideproj.- When
bobrunsshow_trash,bobseestask.txtbut CANNOT seesecret.txt. bobattemptingrestore secret.txtis rejected withpermission denied.
Automated Unit & Integration Tests¶
Run the automated test suite for trash and restore:
Diagrams¶
See the Trash and Restore Flow in the FileServer Engine architecture document for a visual breakdown of soft deletion and restoration operations.