2461ccd469
AtomicWriteFile is useful primitive to use throughout the codebase Change-Id: I338fc4505ba20d5aece09ddc257286f46298e083
43 lines
1018 B
Go
43 lines
1018 B
Go
// Copyright (C) 2019 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package fpath
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/zeebo/errs"
|
|
)
|
|
|
|
// AtomicWriteFile is a helper to atomically write the data to the outfile.
|
|
func AtomicWriteFile(outfile string, data []byte, mode os.FileMode) (err error) {
|
|
// TODO: provide better atomicity guarantees, like fsyncing the parent
|
|
// directory and, on windows, using MoveFileEx with MOVEFILE_WRITE_THROUGH.
|
|
|
|
fh, err := ioutil.TempFile(filepath.Dir(outfile), filepath.Base(outfile))
|
|
if err != nil {
|
|
return errs.Wrap(err)
|
|
}
|
|
defer func() {
|
|
if err != nil {
|
|
err = errs.Combine(err, fh.Close())
|
|
err = errs.Combine(err, os.Remove(fh.Name()))
|
|
}
|
|
}()
|
|
if _, err := fh.Write(data); err != nil {
|
|
return errs.Wrap(err)
|
|
}
|
|
if err := fh.Sync(); err != nil {
|
|
return errs.Wrap(err)
|
|
}
|
|
if err := fh.Close(); err != nil {
|
|
return errs.Wrap(err)
|
|
}
|
|
if err := os.Rename(fh.Name(), outfile); err != nil {
|
|
return errs.Wrap(err)
|
|
}
|
|
return nil
|
|
}
|