[client] Report a partial file drop delivery instead of losing track of it

Delivery moved payloads one at a time and returned on the first failure, and
the caller discarded the paths it returned along with the error. Files that
had already been moved stayed in the destination while the history said the
transfer failed and recorded no path for them, so the user was told nothing
arrived and had nothing to go looking with.

Every item is attempted now, the error names the ones that did not make it,
and the paths that did land are kept on the entry. A transfer settled
elsewhere still keeps the outcome it has, which is what finishTransfer gave.

Delivered names also drop the characters that change how the rest of the name
renders - a U+202E override makes "gpj.exe" display as though it ended in
".jpg" - and are held to one filesystem entry with the extension preserved.
An over-long name used to be refused by the OS, which is the likeliest way to
reach the partial delivery above.
This commit is contained in:
Zoltán Papp
2026-09-08 21:22:43 +02:00
parent ab47d2a4bf
commit 23c88c8b9b
3 changed files with 149 additions and 3 deletions
+10 -1
View File
@@ -606,7 +606,16 @@ func (m *Manager) OnCompleted(offer Offer) {
// Nothing will ask for these payloads again, and a sink that cannot
// address them by path has no sweep of its own to fall back on.
server.Spool().Remove(offer.ID)
m.finishTransfer(offer.ID, StateFailed, err.Error())
// Whatever did land is kept on the entry: those files are in the
// destination whether the rest arrived or not, and a failure with no
// paths would leave the user unable to find them. A transfer already
// settled elsewhere keeps the outcome it has, as finishTransfer would.
if !transfer.terminal() {
transfer.State = StateFailed
transfer.Error = err.Error()
transfer.DeliveredPaths = delivered
m.history.Upsert(transfer)
}
m.emit(EventFailed, m.transferOf(offer.ID))
return
}