2020-01-02 09:47:21 +00:00
|
|
|
|
# src.lwithers.me.uk/go/writefile
|
|
|
|
|
|
2020-01-03 08:49:31 +00:00
|
|
|
|
[![GoDoc](https://godoc.org/src.lwithers.me.uk/go/writefile?status.svg)](https://godoc.org/src.lwithers.me.uk/go/writefile)
|
|
|
|
|
|
2020-01-02 09:47:21 +00:00
|
|
|
|
This package implements the common Unix technique of writing a new file by first
|
|
|
|
|
writing a temporary file, then ensuring it is fsync()ed, before calling rename()
|
|
|
|
|
to atomically move into its final resting place.
|
|
|
|
|
|
|
|
|
|
What problem does this solve? It prevents writing a partial output file, or
|
|
|
|
|
corrupting an existing file with a partially-written new version, if there is a
|
|
|
|
|
crash or other unexpected exit of the program.
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
finalFname, out, err := writefile.New("my-file")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
defer writefile.Abort(out)
|
|
|
|
|
|
|
|
|
|
// … write to ‘out’ …
|
|
|
|
|
|
|
|
|
|
return writefile.Commit(finalFname, out)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `New()` method returns a final filename string which is later passed to
|
|
|
|
|
`Commit()`. This will typically match the filename argument passed to `New()`,
|
|
|
|
|
except if the file is a symlink, in which case the symlink is dereferenced
|
|
|
|
|
and its target is overwritten. If this behaviour is undesired, the following
|
|
|
|
|
pattern may be used instead:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
out, err := writefile.NewNoDeref("my-file")
|
|
|
|
|
// …
|
|
|
|
|
return writefile.Commit("my-file", out)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The temporary file being written will have 0600 permissions. If an existing
|
|
|
|
|
file is overwritten by `Commit()`, the call will attempt to inherit the existing
|
|
|
|
|
permissions. Otherwise, the final file is left with 0600.
|