diff options
author | Martin Czygan <martin.czygan@gmail.com> | 2021-05-20 11:38:47 +0200 |
---|---|---|
committer | Martin Czygan <martin.czygan@gmail.com> | 2021-05-20 11:38:47 +0200 |
commit | 8d4347ce602d51e17c3113edf940ee4d0d78a938 (patch) | |
tree | e9000da17776ab1e7ee44416d1542db542373738 /skate/atomic | |
parent | c0157eb8e09a0d078038df21be2650f0a915250b (diff) | |
download | refcat-8d4347ce602d51e17c3113edf940ee4d0d78a938.tar.gz refcat-8d4347ce602d51e17c3113edf940ee4d0d78a938.zip |
add atomic file ops
Diffstat (limited to 'skate/atomic')
-rw-r--r-- | skate/atomic/file.go | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/skate/atomic/file.go b/skate/atomic/file.go new file mode 100644 index 0000000..1b9bf25 --- /dev/null +++ b/skate/atomic/file.go @@ -0,0 +1,63 @@ +package atomic + +import ( + "io" + "io/ioutil" + "os" + "path" +) + +// WriteFileReader writes data from a reader atomically into filename. +func WriteFileReader(filename string, r io.Reader, perm os.FileMode) error { + dir, name := path.Split(filename) + f, err := ioutil.TempFile(dir, name) + if err != nil { + return err + } + _, err = io.Copy(f, r) + if err == nil { + err = f.Sync() + } + if closeErr := f.Close(); err == nil { + err = closeErr + } + if permErr := os.Chmod(f.Name(), perm); err == nil { + err = permErr + } + if err == nil { + err = os.Rename(f.Name(), filename) + } + // Any err should result in full cleanup. + if err != nil { + os.Remove(f.Name()) + } + return err +} + +// WriteFileAtomic writes the data to a temp file and atomically move if +// everything else succeeds. +func WriteFile(filename string, data []byte, perm os.FileMode) error { + dir, name := path.Split(filename) + f, err := ioutil.TempFile(dir, name) + if err != nil { + return err + } + _, err = f.Write(data) + if err == nil { + err = f.Sync() + } + if closeErr := f.Close(); err == nil { + err = closeErr + } + if permErr := os.Chmod(f.Name(), perm); err == nil { + err = permErr + } + if err == nil { + err = os.Rename(f.Name(), filename) + } + // Any err should result in full cleanup. + if err != nil { + os.Remove(f.Name()) + } + return err +} |