aboutsummaryrefslogtreecommitdiff
path: root/internal/journal/read.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-17 13:58:25 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-17 13:58:25 +0200
commit9ab6686b98499c745024a474a71e3d99b6e14973 (patch)
tree1debf57412d72c6289dd06bd17f0c024a490a3af /internal/journal/read.go
parenta80d470cbad7335fd5e534f32d935e5a49aadb24 (diff)
downloadkrino-9ab6686b98499c745024a474a71e3d99b6e14973.tar.gz
krino-9ab6686b98499c745024a474a71e3d99b6e14973.zip
a chain that deletes itself still gives back the file it displaced
(on-conflict overwrite) trashes the file in the way; ยง7.4 promises undo restores it. Walking a file's log entries stopped dead at a permanent delete, so the displace written earlier in the same chain was never reached: the user's file stayed in the Trash, the refusal named only the file they did not care about, and krino log called the run undone. The displaced file is a different file, so it is offered as its own entry in the undo plan, keyed by its own path - the deleted file stays refused, since nothing of it can come back, and the copy or move that preceded the delete stays unreversed too (undoing a copy whose original was then deleted would destroy the last remaining copy). The accounting matched: every reversible step of a deleted file was subtracted, its displace included, so the run read (undone). Only what genuinely cannot come back is subtracted now. End to end, the scenario from the review: the only copy of a file is displaced by an incoming one that is then permanently deleted. before: archive/ empty, "(undone)", nothing offered after: archive/a.pdf restored, run reads partly undone
Diffstat (limited to 'internal/journal/read.go')
-rw-r--r--internal/journal/read.go19
1 files changed, 17 insertions, 2 deletions
diff --git a/internal/journal/read.go b/internal/journal/read.go
index aa79118..a41cd8a 100644
--- a/internal/journal/read.go
+++ b/internal/journal/read.go
@@ -236,6 +236,7 @@ func Runs(path string, n int) ([]Run, error) {
type fileOf struct{ run, dir, file string }
reversibleOf := map[fileOf]int{}
deletedFile := map[fileOf]bool{}
+ displacedOf := map[fileOf]int{}
for _, line := range lines {
e, ok := parseLine(line)
@@ -259,6 +260,13 @@ func Runs(path string, n int) ([]Run, error) {
if e.Action == "delete" {
deletedFile[fileOf{e.Run, e.Dir, e.File}] = true
}
+ if e.Action == "displace" {
+ // Counted apart from the rest of its file: a permanent
+ // delete ends the file it deleted, but the file that chain
+ // trashed to make room is a different file and can still
+ // come back.
+ displacedOf[fileOf{e.Run, e.Dir, e.File}]++
+ }
}
if e.Action == "run-start" {
if orig, ok := strings.CutPrefix(e.Detail, undoOfPrefix); ok && orig != "" {
@@ -298,9 +306,16 @@ func Runs(path string, n int) ([]Run, error) {
if r.Undone {
took := 0
for f, n := range reversibleOf {
- if f.run == r.ID && !deletedFile[f] {
- took += n
+ if f.run != r.ID {
+ continue
+ }
+ if deletedFile[f] {
+ // Nothing of a permanently deleted file comes back
+ // except what it displaced.
+ took += displacedOf[f]
+ continue
}
+ took += n
}
r.PartlyUndone = reversed[r.ID] < took
}