diff --git a/internal/restore/restore.go b/internal/restore/restore.go index ee510d0..eb175d6 100644 --- a/internal/restore/restore.go +++ b/internal/restore/restore.go @@ -279,12 +279,7 @@ func Run(s *session.Session, dir Direction, opts Options) (*Result, error) { if !act() { continue } - tmp := field(0) + ".undo-xchg" - if err = os.Rename(field(0), tmp); err == nil { - if err = os.Rename(field(1), field(0)); err == nil { - err = os.Rename(tmp, field(1)) - } - } + err = swapAny(field(0), field(1)) case journal.OpMkdir: if dir == Undo { diff --git a/internal/restore/restore_test.go b/internal/restore/restore_test.go index efdaf68..1d6fa22 100644 --- a/internal/restore/restore_test.go +++ b/internal/restore/restore_test.go @@ -188,6 +188,27 @@ func TestDryRunTouchesNothing(t *testing.T) { } } +func TestExchange(t *testing.T) { + work := t.TempDir() + a := filepath.Join(work, "a") + b := filepath.Join(work, "b") + write(t, a, "AAA") + write(t, b, "BBB") + s := newSession(t, []journal.Entry{ + {Op: journal.OpExchange, Fields: []string{a, b}}, + }) + + if _, err := Run(s, Undo, Options{}); err != nil { + t.Fatal(err) + } + if got := read(t, a); got != "BBB" { + t.Fatalf("a = %q, want BBB", got) + } + if got := read(t, b); got != "AAA" { + t.Fatalf("b = %q, want AAA", got) + } +} + func TestSelectiveReplayLeavesStateAndOthers(t *testing.T) { work := t.TempDir() f1 := filepath.Join(work, "one.txt")