The Kalem Book GitHub

This Book describes Kalem's main branch, which may be ahead of the latest release.

D20: File operations

Table of Contents

  • Status: Decided (2026-09-28)
  • Decision: the trash crate (5.x) moves files to the system trash; copy, move, delete and the small operations are Kalem's own code on std::fs, with filetime for modification times. They live in the kalem-fs crate, which runs an operation on a background thread with progress, cancellation and a choice for each conflict.
  • Task: T2.7e.1

1. Candidates

Option For Against
trash + own operations on std::fs trash is the maintained cross-platform trash crate (Recycle Bin on Windows, the freedesktop.org trash on Linux, the Finder or NSFileManager on macOS). Own copy and move code can report progress per file, stop between files and ask about each conflict Recursive copy, merging into existing folders and moves across devices must be written and tested
fs_extra Recursive copy and move with a progress callback Conflict handling is a global overwrite or skip flag; cancellation only by returning from the callback; little maintenance
System tools (cp, mv, trash, PowerShell) Nothing to write Different on every platform, progress and conflicts hard to get, quoting risks

2. Details

  • Trash on macOS. trash defaults to asking the Finder through AppleScript, which makes macOS ask the user to let Kalem control the Finder. Kalem uses the NSFileManager method instead: no permission prompt and no Finder sound; the Finder's "Put Back" may be missing for these files (a macOS limitation the crate documents).
  • Copy. Folders recursively, merging into an existing folder; symbolic links copied as links; permissions (by std::fs::copy) and modification times kept. Copying a file onto itself or a folder into itself is refused before anything is removed.
  • Move. A rename; across devices (ErrorKind::CrossesDevices) a copy and a delete. A folder moved onto an existing folder is merged into it. A change of case only (a.txt to A.txt) on a file system that ignores case is a plain rename.
  • Conflicts. Before an operation starts, the destinations that exist are listed; the user chooses for each one (overwrite, skip, keep both as name (2).ext) or for all that are left. Operation::choices holds the choices by destination.
  • Progress and cancellation. Job::start runs the operation on its own thread: files and bytes are counted first for a copy, progress is kept per file, and cancelling stops between files. The outcome lists what was done, skipped and failed.
  • Not yet. Undo of file operations (T2.7e.7) and restoring from the trash: the trash crate can list and restore on Linux and Windows, not on macOS.