Beide Recherchen zur Map #16 lagen nur auf lokalen Wegwerf-Branches. Die Kurzfassungen stehen an den Tickets #21 und #22, die Langfassungen sind mit Quellen und der Trennung zwischen Belegtem, Abgeleitetem und Unbelegtem aber das, worauf man zurueckkommt. Beide enthalten Messungen, die keine Dokumentation hergibt: dass trash 5.2.6 auf Netzlaufwerken gar nicht funktioniert und Windows dort sonst still und endgueltig loeschen wuerde, und dass ein ungeprunter Append-Log im Yjs-Benchmark das Siebzigfache des Rohtexts misst. Ausserdem /.claude in die .gitignore - dort liegen lokale Einstellungen und die temporaeren Worktrees der Recherche-Agenten.
27 KiB
Papierkorb unter Rust: Crate, Netzlaufwerke, Kosten
Gitea-Issue: #21 · Stand der Recherche: 2026-08-28
Umfeld: DioNotes, Rust (edition 2021), Dioxus 0.7.1, Default-Feature desktop.
Entwicklung und Messung unter Windows 11 Enterprise 10.0.26200, cargo/rustc 1.96.0.
Alle Aussagen sind als [belegt] (Primärquelle mit URL, Quellcode, oder eigene reproduzierbare Messung) oder [Vermutung] (Schlussfolgerung ohne deckende Quelle) markiert.
Besonderheit dieser Recherche: Die Kernfrage — was auf Netzlaufwerken passiert — wurde nicht erschlossen, sondern gemessen. Auf dem Entwicklungsrechner sind SMB-Netzlaufwerke gemountet (
Z:→\\la-nas-01.ad.datawin.de\Scan). Es wurden drei kleine Wegwerf-Programme außerhalb des Repos gebaut und ausgeführt. Die Rohausgaben stehen in Abschnitt 4. Im Repo wurde keine Dependency hinzugefügt;Cargo.tomlundCargo.locksind unverändert.
1. Kurzantwort
Die Crate ist trash, aktuell 5.2.6 (veröffentlicht 2026-05-03). Sie ist der De-facto-Standard
und wird gepflegt.
Aufruf:
trash::delete(&pfad)?; // eine Datei
trash::delete_all(&pfade)?; // mehrere
Kosten: +6 Pakete im Windows-Graphen. Das ist nicht über Cargo-Features reduzierbar —
das im Ticket vermutete Gegenstück zum rfd/Wayland-Fall gibt es hier nicht. Fünf der sechs
Pakete sind eine zweite, ältere Kopie der windows-Crate-Familie (0.56 neben dem bereits
vorhandenen 0.61.3), weil trash 5.2.6 noch auf windows 0.56.0 festgenagelt ist.
Netzlaufwerke — und hier wird es unangenehm, es sind zwei getrennte Probleme:
-
trash 5.2.6funktioniert auf Netzlaufwerken schlicht gar nicht. Der Aufruf schlägt mit einer irreführenden Meldung fehl (0x80070002, „Das System kann die angegebene Datei nicht finden"), die Datei bleibt unangetastet liegen. Ursache ist ein Pfad-Bug in der Crate, kein Papierkorb-Thema. Immerhin: nichts geht verloren. -
Wäre der Bug behoben, wäre das Verhalten gefährlich. Ruft man dieselbe Windows-API mit denselben Flags, aber unverbogenem Pfad auf, dann wird die Datei auf dem Netzlaufwerk endgültig und stillschweigend gelöscht —
PerformOperations()liefertOk(()),GetAnyOperationsAborted()liefertfalse. Am Rückgabewert ist der Fall nicht vom erfolgreichen Papierkorb-Verschieben zu unterscheiden.
Die Antwort auf die eigentliche Ticketfrage lautet also: Ja, die App braucht eine Vorab-Prüfung
bzw. Rückfrage. Sich auf Ok(()) zu verlassen, reicht nicht.
Erkennen lässt sich der Fall zuverlässig — aber nur über IFileOperationProgressSink, den
trash nicht durchreicht (die Crate übergibt hart None). Details in Abschnitt 5.
Blockierend. Die Dauer ist unabhängig von der Dateigröße (Verschieben innerhalb des Volumes); gemessen: ~740 ms beim allerersten Aufruf (COM-Initialisierung), danach ~27 ms. Abschnitt 6.
2. Welche Crate, wird sie gepflegt?
[belegt]
trash, aktuelle Version5.2.6, veröffentlicht 2026-05-03, nicht zurückgezogen. 2.683.466 Downloads gesamt, 724.229 „recent". Beschreibung: „A library for moving files and folders to the Recycle Bin". → https://crates.io/api/v1/crates/trash- Letzte Releases: 5.2.6 (2026-05-03), 5.2.5 (2025-10-25), 5.2.4 (2025-10-24), 5.2.3 (2025-08-15), 5.2.2 (2025-02-22). Also regelmäßige Releases, zuletzt vor knapp vier Monaten. → https://crates.io/api/v1/crates/trash
- Das in
Cargo.tomleingetragene Repository isthttps://github.com/ArturKovacs/trash; gepflegt und released wird faktisch aus dem Fork https://github.com/Byron/trash-rs (251 Sterne), auf den auch die CI-Badges und alle Changelog-Commit-Links zeigen. →trash-5.2.6/README.md,trash-5.2.6/CHANGELOG.md - Unterstützte Plattformen laut README: „Windows, macOS, and all FreeDesktop Trash compliant
environments (including GNOME, KDE, XFCE, and more)".
→
trash-5.2.6/README.md rust-version = "1.85.0",edition = "2021", Lizenz MIT. →trash-5.2.6/Cargo.toml- Das Changelog von 5.2.6 zeigt echte, inhaltliche Wartung (Panic durch sauberen Fehler ersetzt,
weil
cosmic-filesabstürzte) — die Crate hat reale, anspruchsvolle Nutzer. →trash-5.2.6/CHANGELOG.md
[Vermutung]
Es gibt keine ernstzunehmende Alternative. rrecycle und recyclebin tauchen in der Suche auf,
sind aber ungleich kleiner und teils reine CLI-Werkzeuge. Für DioNotes ist trash gesetzt.
3. Was kostet das im Abhängigkeitsgraphen?
Das Ticket fragt gezielt nach einem Gegenstück zum rfd-Fall, wo sich neun Wayland-Pakete durch
Angleichen der Features an dioxus-desktop vollständig vermeiden ließen.
[belegt] Antwort: Ein solches Gegenstück gibt es nicht.
Die Features von trash 5.2.6 lauten wörtlich:
[features]
coinit_apartmentthreaded = []
coinit_disable_ole1dde = []
coinit_multithreaded = []
coinit_speed_over_memory = []
default = ["coinit_apartmentthreaded", "chrono"]
→ trash-5.2.6/Cargo.toml
Alle vier coinit_*-Features haben leere Dependency-Listen — es sind reine cfg-Schalter für
den COM-Initialisierungsmodus (COINIT_APARTMENTTHREADED vs. COINIT_MULTITHREADED), ohne
jede Wirkung auf den Graphen.
→ trash-5.2.6/src/windows.rs, struct CoInitializer
Das einzige dependency-wirksame Feature ist chrono, und das ist ausschließlich unter
cfg(all(unix, not(macos), not(ios), not(android))) deklariert. Auf Windows ist es
wirkungslos.
→ trash-5.2.6/Cargo.toml, Abschnitt [target.'cfg(all(unix, …))'.dependencies.chrono]
[belegt] Gemessene Zahlen
Basis: Cargo.lock im Repo mit 745 Paketen; cargo tree --edges normal ergibt 419 eindeutige
Pakete für x86_64-pc-windows-msvc und 470 für x86_64-unknown-linux-gnu.
| Variante | Windows-Target | Linux-Target |
|---|---|---|
cargo add trash (default) |
+6 (419 → 425) | +4 (470 → 474) |
cargo add trash --no-default-features |
+6 (keine Ersparnis) | +2 (470 → 472) |
Die sechs neuen Pakete auf Windows:
trash v5.2.6
windows v0.56.0
windows-core v0.56.0
windows-implement v0.56.0 (proc-macro)
windows-interface v0.56.0 (proc-macro)
windows-result v0.1.2
[belegt] Warum die windows-Pakete nicht „gratis" sind
Sie stehen zwar bereits namentlich im Cargo.lock, aber in semver-inkompatiblen Versionen,
werden also nicht dedupliziert:
| Crate | schon im Lock (via dioxus/wry) | von trash gefordert |
dedupliziert? |
|---|---|---|---|
windows |
0.61.3 | 0.56.0 | nein |
windows-core |
0.61.2 | 0.56.0 | nein |
windows-implement |
0.60.2 | 0.56.0 | nein |
windows-interface |
0.59.3 | 0.56.0 | nein |
windows-result |
0.3.4 | 0.1.2 | nein |
cargo tree -i windows@0.56.0 bestätigt: trash ist der einzige Konsument dieser zweiten Kopie.
Wirklich gratis sind nur log (0.4.33) und scopeguard (1.2.0), die bereits passend im Graphen
stehen.
[belegt] Auf Linux kostet es fast nichts
Die FreeDesktop-Implementierung ist reines Rust (libc, once_cell, scopeguard, urlencoding,
optional chrono). Kein GTK, kein dbus, kein zbus — der rfd-artige Fallstrick existiert hier
nicht.
→ trash-5.2.6/Cargo.toml
Mit --no-default-features fielen auf Linux chrono + iana-time-zone weg (+2 statt +4). Preis:
trash kann dann keinen DeletionDate-Zeitstempel in die .trashinfo-Dateien schreiben. Das ist
funktional relevant, nicht bloß kosmetisch. [Vermutung] Für DioNotes wäre der Verzicht auf zwei
Pakete den Verlust der Zeitstempel nicht wert.
[Vermutung] Der einzige echte Hebel
Ein künftiges trash-Release, das auf windows ≥ 0.61 aktualisiert, würde die gesamte
windows-Familie mit dem bestehenden dioxus/wry-Graphen deduplizieren. Der Windows-Delta fiele
dann von 6 auf 1 (nur trash selbst). Das ist nichts, worauf man warten sollte, aber es ist der
Grund, die Version im Blick zu behalten.
4. Netzlaufwerke und USB-Sticks — die Kernfrage
Das Ticket fragt: Fällt der Aufruf still auf endgültiges Löschen zurück, oder schlägt er fehl?
Die Antwort hat zwei Schichten, und sie sind unabhängig voneinander.
4.1 [belegt] Schicht 1: trash 5.2.6 schlägt auf Netzlaufwerken fehl — wegen eines Pfad-Bugs
Gemessen, Wegwerf-Programm gegen trash 5.2.6, Datei auf Z:\ (SMB-Share):
=== C: Netzlaufwerk SMB, klein | dir=Z:\ | 1024 bytes ===
angelegt: Z:\dionotes-trashprobe-net-small.md
trash::delete -> Err(Os { code: -2147024894,
description: "windows error: Das System kann die angegebene Datei nicht finden. (0x80070002)" })
Dauer: 31.0407ms
Datei existiert noch? true
Papierkorb-Treffer: vorher=0 nachher=0 => IM PAPIERKORB: false
Zum Vergleich, dieselbe Operation lokal auf NTFS:
=== A: lokal NTFS, klein | dir=C:\…\Temp | 1024 bytes ===
trash::delete -> Ok(())
Dauer: 740.7595ms
Datei existiert noch? false
Papierkorb-Treffer: vorher=0 nachher=1 => IM PAPIERKORB: true
Die Datei auf dem Netzlaufwerk bleibt liegen. Es geht nichts verloren, aber es passiert auch
nichts. Das reproduziert exakt den seit 2022-08-07 offenen Bug
trash-rs#55 „Unable to delete file on Windows shared folder"
(Label help wanted, bis heute ungelöst).
Die Ursache, aus dem Quellcode und nachgemessen:
trash kanonisiert jeden Pfad vor dem Löschen mit std::fs::canonicalize:
let canonical_parent = parent.canonicalize()
.map_err(|_| Error::CanonicalizePath { original: parent.to_owned() })?;
→ trash-5.2.6/src/lib.rs, fn canonicalize_paths
windows.rs schneidet danach stumpf die ersten vier UTF-16-Zeichen \\?\ ab:
let path_prefix = ['\\' as u16, '\\' as u16, '?' as u16, '\\' as u16];
let wide_path_container = to_wide_path(full_path);
let wide_path_slice = if wide_path_container.starts_with(&path_prefix) {
&wide_path_container[path_prefix.len()..]
} else {
&wide_path_container[0..]
};
→ trash-5.2.6/src/windows.rs
Das geht für lokale Pfade gut und für UNC-Pfade schief. Gemessen:
### canonicalize-Verhalten fuer lokal C:
canonicalize() = "\\?\C:\Users\marvin.dietermann\AppData\Local\Temp"
nach dem Prefix-Stripping = "C:\Users\marvin.dietermann\AppData\Local\Temp" <- gültig
### canonicalize-Verhalten fuer Netzlaufwerk Z:
canonicalize() = "\\?\UNC\la-nas-01.ad.datawin.de\Scan"
nach dem Prefix-Stripping = "UNC\la-nas-01.ad.datawin.de\Scan" <- Unsinn
### canonicalize-Verhalten fuer UNC-Pfad \\la-nas-01.ad.datawin.de\Scan
canonicalize() = "\\?\UNC\la-nas-01.ad.datawin.de\Scan"
nach dem Prefix-Stripping = "UNC\la-nas-01.ad.datawin.de\Scan" <- Unsinn
Aus \\?\UNC\server\share wird UNC\server\share — ein Pfad, den es nicht gibt.
SHCreateItemFromParsingName scheitert daran mit 0x80070002. Korrekt wäre die Rückübersetzung
nach \\server\share.
Betroffen sind beide Schreibweisen — der gemappte Laufwerksbuchstabe Z:\ genauso wie der
direkte UNC-Pfad, weil canonicalize beide auf dieselbe \\?\UNC\…-Form abbildet.
4.2 [belegt] Schicht 2: Windows selbst löscht auf Netzlaufwerken still und endgültig
Um Crate-Bug von Betriebssystemverhalten zu trennen, wurde IFileOperation direkt aufgerufen —
mit exakt denselben Flags wie trash (FOF_NO_UI | FOF_ALLOWUNDO | FOF_WANTNUKEWARNING,
zusammen 0x00004654), aber mit unverbogenem Pfad:
### IFileOperation direkt auf lokal C:
PerformOperations -> Ok(()) (Dauer 102.5266ms)
GetAnyOperationsAborted -> false
Datei existiert noch? false
Papierkorb-Treffer: 1 <- im Papierkorb
### IFileOperation direkt auf Netzlaufwerk Z:
PerformOperations -> Ok(()) (Dauer 405.4515ms)
GetAnyOperationsAborted -> false
Datei existiert noch? false
Papierkorb-Treffer: 0 <- WEG. endgueltig.
### IFileOperation direkt auf UNC-Pfad \\la-nas-01.ad.datawin.de\Scan
PerformOperations -> Ok(()) (Dauer 299.5401ms)
GetAnyOperationsAborted -> false
Datei existiert noch? false
Papierkorb-Treffer: 0 <- WEG. endgueltig.
Das ist die eigentliche Warnung des Tickets. Auf dem Netzlaufwerk wird die Datei endgültig
gelöscht, und die API meldet denselben Erfolg wie beim Verschieben in den Papierkorb:
Ok(()) und GetAnyOperationsAborted() == false. Am Rückgabewert ist der Unterschied nicht
erkennbar.
Bemerkenswert: FOF_WANTNUKEWARNING hat keinen Dialog ausgelöst. Microsoft dokumentiert das
Flag als „Send a warning if a file or folder is being destroyed during a delete operation rather
than recycled. This flag partially overrides FOF_NOCONFIRMATION."
→ https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifileoperation-setoperationflags
[Vermutung] Die Warnung unterbleibt, weil trash zusätzlich FOF_SILENT und FOF_NOERRORUI
setzt: FOF_NO_UI ist in der windows-Crate als 1556u32 = 0x614 definiert, also
FOF_SILENT (0x4) | FOF_NOCONFIRMATION (0x10) | FOF_NOCONFIRMMKDIR (0x200) | FOF_NOERRORUI (0x400).
→ windows-0.56.0/src/Windows/Win32/UI/Shell/mod.rs, pub const FOF_NO_UI
Das „partially overrides" bezieht sich laut Doku nur auf FOF_NOCONFIRMATION, nicht auf
FOF_SILENT/FOF_NOERRORUI. Belegt ist jedenfalls das Ergebnis: kein Dialog, keine Rückfrage,
Datei weg.
4.3 USB-Sticks und andere Dateisysteme — [nicht belastbar beantwortet]
Das konnte nicht gemessen werden. Auf dem Testrechner sind zwar zwei Wechseldatenträger
(D:, E:) angemeldet, beide sind aber leer (FileSystemType = Unknown, SizeRemaining = 0) —
offensichtlich Kartenleser ohne Medium. Ohne echten FAT32-/exFAT-Stick lässt sich der Fall nicht
verifizieren.
[Vermutung], ausdrücklich als solche gekennzeichnet: Lokale Wechseldatenträger verhalten sich
anders als Netzlaufwerke; Windows legt auf ihnen üblicherweise sehr wohl einen $RECYCLE.BIN-
bzw. RECYCLER-Ordner an. Der kritische Fall ist damit [Vermutung] primär das Netzlaufwerk.
Verlassen sollte man sich darauf nicht — die in Abschnitt 5 beschriebene Erkennung deckt beide
Fälle ab, ohne dass man vorher wissen muss, welcher vorliegt. Vor der Implementierung sollte
dieser Fall mit einem echten USB-Stick nachgemessen werden.
Ebenfalls [Vermutung]: Auch auf lokalem NTFS kann der Papierkorb fehlen — er lässt sich pro Volume in den Papierkorb-Eigenschaften deaktivieren („Dateien sofort löschen"), und Dateien oberhalb der konfigurierten Maximalgröße gehen ebenfalls direkt verloren. Eine Prüfung, die nur auf den Laufwerkstyp schaut, greift deshalb zu kurz.
5. Wie erfährt das Programm, welcher Fall eingetreten ist?
[belegt] Über den Rückgabewert von trash: gar nicht
trash::delete liefert Result<(), Error>. Die Error-Varianten sind Unknown, Os,
FileSystem (nur FreeDesktop), TargetedRoot, CouldNotAccess, CanonicalizePath,
ConvertOsString, RestoreCollision, RestoreTwins.
→ https://docs.rs/trash/5.2.6/src/trash/lib.rs.html
Es gibt keine Variante und kein Erfolgs-Detail, das „endgültig gelöscht statt Papierkorb"
ausdrückt. Wie Abschnitt 4.2 zeigt, kommt in diesem Fall schlicht Ok(()) zurück.
Die Crate wertet lediglich GetAnyOperationsAborted() aus, und das war im Netzlaufwerk-Fall
false:
pfo.PerformOperations()?;
if pfo.GetAnyOperationsAborted()?.as_bool() {
// TODO: return the reason why the operation was aborted.
return Err(Error::Unknown { description: "Some operations were aborted".into() });
}
→ trash-5.2.6/src/windows.rs
[belegt] Über IFileOperationProgressSink: zuverlässig — aber trash reicht ihn nicht durch
Microsoft dokumentiert für IFileOperationProgressSink::PostDeleteItem den Parameter
psiNewlyCreated wörtlich so:
„A pointer to an IShellItem that specifies the deleted item, now in the Recycle Bin. If the item was fully deleted, this value is NULL."
Genau das wurde nachgemessen — ein eigener Sink, angehängt an DeleteItem:
### lokal C:
[sink] PreDeleteItem dwFlags=0x00000282
[sink] PostDeleteItem dwFlags=0x00000282 hrDelete=0x00270008 psiNewlyCreated=Some
==> IM PAPIERKORB: true
neuerPfad=Some("C:\$Recycle.Bin\S-1-5-21-…-1668\$R1V9IFD.md")
### Netzlaufwerk Z:
[sink] PreDeleteItem dwFlags=0x00000202
[sink] PostDeleteItem dwFlags=0x00000202 hrDelete=0x00270008 psiNewlyCreated=NULL
==> IM PAPIERKORB: false
neuerPfad=None
Zwei verwertbare Signale, beide belegt:
-
psiNewlyCreatedinPostDeleteItem—Some⇒ im Papierkorb (inklusive konkretem Pfad im$Recycle.Bin),NULL⇒ endgültig gelöscht. Das ist die verlässliche Nachher-Auskunft.hrDeletetaugt nicht dafür: es war in beiden Fällen identisch0x00270008. -
dwFlagsschon inPreDeleteItem, also vor dem Löschen. Die Differenz zwischen0x282und0x202ist genau0x80— und das istTSF_DELETE_RECYCLE_IF_POSSIBLE:pub const TSF_DELETE_RECYCLE_IF_POSSIBLE: _TRANSFER_SOURCE_FLAGS = _TRANSFER_SOURCE_FLAGS(128i32); pub const TSF_COPY_LOCALIZED_NAME: _TRANSFER_SOURCE_FLAGS = _TRANSFER_SOURCE_FLAGS(512i32); pub const TSF_OVERWRITE_EXIST: _TRANSFER_SOURCE_FLAGS = _TRANSFER_SOURCE_FLAGS(2i32);→
windows-0.56.0/src/Windows/Win32/UI/Shell/mod.rsAuf
C:ist das Bit gesetzt, aufZ:fehlt es. Windows sagt also imPreDeleteItem-Callback von sich aus, ob es recyceln wird — bevor irgendetwas passiert ist.Und man kann an dieser Stelle abbrechen: Microsoft dokumentiert für die Sink-Rückgabewerte „Returns S_OK if successful, or an error value otherwise. In the case of an error value, all subsequent operations pending from the call to IFileOperation are canceled." → https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifileoperationprogresssink-postdeleteitem [Vermutung] Damit ließe sich aus
PreDeleteItemheraus vetoen und stattdessen erst der Nutzer fragen. Der Abbruch ausPreDeleteItemwurde nicht gemessen.
Der Haken: trash übergibt den Sink-Parameter hart als None:
pfo.DeleteItem(&shi, None)?;
→ trash-5.2.6/src/windows.rs
Über die Crate-API ist an diese Information nicht heranzukommen.
[Vermutung] Konsequenz für DioNotes
Drei gangbare Wege, in aufsteigender Sauberkeit:
- Billig und grob: vor dem Löschen prüfen, ob der Workspace-Pfad auf einem Netzlaufwerk liegt
(Laufwerkstyp
DRIVE_REMOTEbzw. UNC-Pfad), und dann eine Rückfrage stellen. Erkennt den Hauptfall, aber nicht den deaktivierten Papierkorb auf lokalem NTFS. - Nachher-Prüfung: nach
trash::deletepertrash::os_limited::list()nachsehen, ob der Eintrag im Papierkorb aufgetaucht ist. Funktioniert (so wurden die Messungen oben verifiziert), ist aber langsam und rennt gegen Race Conditions. - Sauber:
IFileOperationmit eigenem Sink selbst aufrufen, statttrashzu benutzen — dann bekommt manTSF_DELETE_RECYCLE_IF_POSSIBLEvorab undpsiNewlyCreatedhinterher, und der UNC-Bug aus 4.1 entfällt ebenfalls, weil mancanonicalizenicht braucht. Kostet dafür eine eigene Windows-Implementierung und hilft auf Linux/macOS nicht.
Da trash 5.2.6 auf Netzlaufwerken ohnehin nicht funktioniert, ist die Entscheidung ohne eine
bewusste Behandlung dieses Falls nicht vollständig — deshalb ist dieses Ticket die
Voraussetzung für die Lösch-Implementierung, nicht bloß eine Fußnote.
6. Blockierend oder asynchron? Wie lange dauert es?
[belegt] Blockierend
trash::delete ist eine gewöhnliche synchrone Funktion; es gibt keine async-Variante in der
öffentlichen API. Der Windows-Pfad ruft pfo.PerformOperations() direkt im aufrufenden Thread auf,
ohne Thread zu spawnen.
→ trash-5.2.6/src/windows.rs, https://docs.rs/trash/5.2.6/src/trash/lib.rs.html
[belegt] Gemessene Dauer
| Fall | Größe | Dauer |
|---|---|---|
| lokal NTFS, erster Aufruf im Prozess | 1 KiB | 740,8 ms |
| lokal NTFS, zweiter Aufruf | 512 MiB | 26,7 ms |
IFileOperation direkt, lokal |
5 B | 102,5 ms |
IFileOperation direkt, Netzlaufwerk Z: |
5 B | 405,5 ms |
IFileOperation direkt, UNC-Pfad |
5 B | 299,5 ms |
Die Dateigröße spielt praktisch keine Rolle: 512 MiB wurden in 26,7 ms erledigt — schneller als die 1-KiB-Datei davor. Das Verschieben in den Papierkorb ist ein Rename innerhalb desselben Volumes, es werden keine Daten kopiert.
Was kostet, ist der erste Aufruf im Prozess: die COM-Initialisierung
(CoInitializeEx + CoCreateInstance der FileOperation-Klasse) schlägt mit gut 0,7 s zu Buche.
trash initialisiert COM thread_local und einmalig.
→ trash-5.2.6/src/windows.rs, thread_local! { static CO_INITIALIZER … }
[Vermutung] Für DioNotes heißt das: der Aufruf gehört nicht in den UI-Thread. Ein
spawn_blocking bzw. der tokio-Threadpool genügt völlig; eine Fortschrittsanzeige braucht es
für einzelne .md-Dateien nicht. Netzlaufwerke sind mit ~0,3–0,4 s deutlich träger als lokale
Platten, aber immer noch weit unter jeder Schmerzgrenze.
Achtung [belegt]: trash initialisiert COM standardmäßig mit COINIT_APARTMENTTHREADED
(Feature coinit_apartmentthreaded, Teil der Defaults) und panickt, wenn CoInitializeEx
fehlschlägt:
panic!("Call to CoInitializeEx failed. HRESULT: {:?}. Consider using `trash` with the feature `coinit_multithreaded`", hr);
→ trash-5.2.6/src/windows.rs
[Vermutung] Ruft man trash aus einem Tokio-Worker-Thread auf, der bereits als MTA
initialisiert wurde, könnte das zuschlagen; dann ist default-features = false plus
features = ["coinit_multithreaded"] der Ausweg. Das wurde nicht gemessen.
7. macOS und Linux
[belegt] macOS
trash bietet zwei Verfahren, wählbar über TrashContext:
DeleteMethod::Finder(Default) — steuert den Finder per AppleScript.DeleteMethod::NsFileManager— rufttrashItemAtURLaufNSFileManagerauf. Laut den Doc-Kommentaren: „Somewhat faster than theFindermethod", „Does not require additional permissions", „Does not produce the sound that Finder usually makes", aber „Does not show the 'Put Back' option on some systems … This is a macOS bug."
→ trash-5.2.6/src/macos/mod.rs
Fehler von trashItemAtURL werden als Error::Unknown weitergereicht, nicht verschluckt.
Abhängigkeiten: objc2, objc2-foundation, percent-encoding — alle drei stehen bereits im
Cargo.lock (0.6.4 / 0.3.2 / 2.3.2), auf macOS wäre trash also nahezu gratis.
[belegt] Linux / FreeDesktop
Implementiert die FreeDesktop-Trash-Spezifikation v1.0. Die Implementierung ist reines Rust, ohne GTK/dbus. Wichtig für die Netzlaufwerk-Frage: Der Code legt die Trash-Ordner bei Bedarf an und fällt bei einem geräteübergreifenden Verschieben explizit auf Kopieren-und-Löschen zurück:
let Err(e) = std::fs::rename(src, dst) else { return Ok(()) };
let needs_cross_device_copy = e.kind() == ErrorKind::CrossesDevices;
if !needs_cross_device_copy { return Err((src.to_owned(), e)); }
debug!("Cross-device move detected, falling back to copy+delete for {:?}", src);
→ trash-5.2.6/src/freedesktop.rs
[Vermutung] Damit ist Linux der unproblematischere Fall: Entweder die Datei landet in einem
Trash-Verzeichnis, oder es kommt ein Error::FileSystem zurück. Ein stilles endgültiges Löschen
wie unter Windows ist im Code nicht angelegt. Nicht gemessen — es stand keine Linux-Maschine zur
Verfügung.
8. Empfehlung
[Vermutung] — das ist eine Einschätzung, keine belegte Aussage:
trash 5.2.6nehmen, mit Default-Features. Die +6 Pakete sind der Preis; verhandeln lässt sich daran nichts.- Den Netzlaufwerk-Fall vor der ersten Löschfunktion klären, nicht danach.
trashschlägt dort heute fehl (4.1) — die App muss diesen Fehler ohnehin abfangen und dem Nutzer erklären, sonst wirkt das Löschen auf Netzlaufwerken schlicht kaputt. - Eine Rückfrage vor dem Löschen ist nötig, sobald der Workspace nicht auf einer lokalen
Platte liegt. Der Nutzer muss wissen, ob seine Notiz wiederherstellbar ist — und aus dem
Rückgabewert von
trasherfährt er es nicht (5). - Nicht im UI-Thread aufrufen (6).
- Die
trash-Version im Blick behalten: sobald sie aufwindows≥ 0.61 geht, halbieren sich die Kosten, undtrash-rs#55könnte bei der Gelegenheit mit erledigt werden.
9. Reproduktion
Die Messungen stammen aus drei Wegwerf-Programmen, die außerhalb des Repos gebaut wurden (Scratchpad, nicht eingecheckt):
main.rs—trash::deletegegen lokal / Netzlaufwerk, mit Papierkorb-Gegenprobe übertrash::os_limited::list()raw.rs—IFileOperationdirekt, mit denselben Flags, ohnecanonicalize; zeigt zusätzlich das Prefix-Stripping-Verhaltensink.rs— eigenerIFileOperationProgressSink(#[implement]auswindows 0.56), protokolliertPreDeleteItem/PostDeleteItem
Alle angelegten Testdateien wurden wieder entfernt, die Papierkorb-Einträge mit
trash::os_limited::purge_all endgültig gelöscht. Auf Z: sind keine Rückstände verblieben.
Im Repo wurde nichts an Cargo.toml oder Cargo.lock geändert — die Dependency-Messung lief
über cargo add mit anschließendem git checkout --, verifiziert mit leerem
git status --porcelain.
10. Quellen
- crates.io-API zu
trash: https://crates.io/api/v1/crates/trash - API-Doku: https://docs.rs/trash/latest/trash/
- Quelltext
lib.rs(Error-Enum,canonicalize_paths): https://docs.rs/trash/5.2.6/src/trash/lib.rs.html - Quelltext
windows.rs,freedesktop.rs,macos/mod.rs,Cargo.toml,README.md,CHANGELOG.md: aus dem Crate-Tarball https://static.crates.io/crates/trash/5.2.6/download (auf docs.rs nicht einsehbar — docs.rs baut auf Linux,windows.rsist dort wegcfg-t) - Repository (gepflegter Fork): https://github.com/Byron/trash-rs
- Offener Bug zum Netzlaufwerk-Fall: https://github.com/Byron/trash-rs/issues/55
IFileOperation::SetOperationFlags(FOF_-/FOFX_-Flags,FOF_WANTNUKEWARNING): https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifileoperation-setoperationflagsIFileOperationProgressSink::PostDeleteItem(psiNewlyCreatedist NULL bei endgültiger Löschung): https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifileoperationprogresssink-postdeleteitem- Konstanten
FOF_NO_UI,TSF_DELETE_RECYCLE_IF_POSSIBLEu. a.: generierte Bindings inwindows 0.56.0,src/Windows/Win32/UI/Shell/mod.rs - FreeDesktop Trash Specification v1.0: https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html