Explorar el Código

fix: atomic killist save via temp file + rename

os.Create truncates the target immediately; a failed write or flush
leaves the file empty/corrupt. Write to a temp file in the same
directory, flush, close, then os.Rename — the rename is atomic on
Windows (same volume). Also check WriteString return values.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
master
Jan Svabenik hace 1 mes
padre
commit
813e38f193
Se han modificado 1 ficheros con 24 adiciones y 5 borrados
  1. +24
    -5
      internal/killist/killist.go

+ 24
- 5
internal/killist/killist.go Ver fichero

@@ -6,6 +6,7 @@ package killist
import (
"bufio"
"os"
"path/filepath"
"strings"
"sync"
)
@@ -79,15 +80,33 @@ func (kl *KillList) List() []string {
return out
}

// save writes the kill list atomically: it writes to a temp file in the same
// directory, flushes, closes, then renames over the target. This ensures the
// existing file is never truncated on a partial write or flush error.
func (kl *KillList) save() error {
f, err := os.Create(kl.filepath)
dir := filepath.Dir(kl.filepath)
tmp, err := os.CreateTemp(dir, ".killist-*.tmp")
if err != nil {
return err
}
defer f.Close()
w := bufio.NewWriter(f)
tmpName := tmp.Name()

w := bufio.NewWriter(tmp)
for t := range kl.titles {
w.WriteString(t + "\n")
if _, err := w.WriteString(t + "\n"); err != nil {
tmp.Close()
os.Remove(tmpName)
return err
}
}
if err := w.Flush(); err != nil {
tmp.Close()
os.Remove(tmpName)
return err
}
if err := tmp.Close(); err != nil {
os.Remove(tmpName)
return err
}
return w.Flush()
return os.Rename(tmpName, kl.filepath)
}

Cargando…
Cancelar
Guardar