Harden report output publication
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -14,15 +15,35 @@ const (
|
||||
)
|
||||
|
||||
// ValidateAtomicPath verifies that the final path can be safely used with this
|
||||
// package's same-directory atomic-write implementation.
|
||||
// package's same-directory atomic-write implementation. It accepts only an
|
||||
// absent path or an existing regular file.
|
||||
func ValidateAtomicPath(path string) error {
|
||||
if len(filepath.Base(path)) > maxFileNameBytes {
|
||||
return fmt.Errorf("final file name exceeds the %d-byte limit", maxFileNameBytes)
|
||||
}
|
||||
info, err := os.Lstat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("inspect final destination %q: %w", path, err)
|
||||
}
|
||||
if !info.Mode().IsRegular() {
|
||||
return fmt.Errorf("final destination %q must be absent or a regular file", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteFileAtomic(path string, data []byte) error {
|
||||
return WriteFileAtomicContext(context.Background(), path, data)
|
||||
}
|
||||
|
||||
// WriteFileAtomicContext writes data through a same-directory temporary file.
|
||||
// It checks cancellation immediately before the rename that publishes the file.
|
||||
func WriteFileAtomicContext(ctx context.Context, path string, data []byte) error {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
if err := ValidateAtomicPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -42,6 +63,12 @@ func WriteFileAtomic(path string, data []byte) error {
|
||||
if err := tmp.Close(); err != nil {
|
||||
return fmt.Errorf("close temporary file for %q: %w", path, err)
|
||||
}
|
||||
if err := ValidateAtomicPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(tmpName, path); err != nil {
|
||||
return fmt.Errorf("save %q: %w", path, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user