diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-27 08:16:22 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-27 08:16:22 +0300 |
| commit | 734c7fbd89241133499a88674d5cf62de2ca1469 (patch) | |
| tree | 90aa48f5f892903a059b56e075e81821bcbda998 /internal/generator/generator.go | |
| parent | 371c54cb5ad3793cf4b61e7451b0710d317021d6 (diff) | |
fix(generator): write to temp file, check close error, rename on success
Fixes data loss risk in writePage:
- Write to a temp file instead of the target path.
- Explicitly close the temp file and check the error (was ignored).
- Rename to the final path only after successful close.
- Remove the temp file on any error so truncated output is never left on disk.
Added TestWritePage (happy path + template error) and
TestWritePage_tempFileCleanedOnError to verify no corruption of existing file.
Diffstat (limited to 'internal/generator/generator.go')
| -rw-r--r-- | internal/generator/generator.go | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 079cc38..0b51edd 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -199,16 +199,33 @@ func writePage(tmpl *template.Template, posts []*post.Post, pageIndex, totalPage filename := pageFilename(pageIndex) path := filepath.Join(cfg.OutputDir, filename) - f, err := os.Create(path) + tmpFile, err := os.CreateTemp(cfg.OutputDir, filename+".*.tmp") if err != nil { - return fmt.Errorf("create %s: %w", filename, err) + return fmt.Errorf("create temp for %s: %w", filename, err) } - defer f.Close() + tmpPath := tmpFile.Name() - if err := tmpl.Execute(f, data); err != nil { + ok := false + defer func() { + _ = tmpFile.Close() + if !ok { + _ = os.Remove(tmpPath) + } + }() + + if err := tmpl.Execute(tmpFile, data); err != nil { return fmt.Errorf("render %s: %w", filename, err) } + if err := tmpFile.Close(); err != nil { + return fmt.Errorf("close temp %s: %w", filename, err) + } + + if err := os.Rename(tmpPath, path); err != nil { + return fmt.Errorf("rename %s: %w", filename, err) + } + + ok = true return nil } |
