github.com/kobeld/docker@v1.12.0-rc1/pkg/ioutils/fswriters.go (about) 1 package ioutils 2 3 import ( 4 "io" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 ) 9 10 // NewAtomicFileWriter returns WriteCloser so that writing to it writes to a 11 // temporary file and closing it atomically changes the temporary file to 12 // destination path. Writing and closing concurrently is not allowed. 13 func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, error) { 14 f, err := ioutil.TempFile(filepath.Dir(filename), ".tmp-"+filepath.Base(filename)) 15 if err != nil { 16 return nil, err 17 } 18 abspath, err := filepath.Abs(filename) 19 if err != nil { 20 return nil, err 21 } 22 return &atomicFileWriter{ 23 f: f, 24 fn: abspath, 25 }, nil 26 } 27 28 // AtomicWriteFile atomically writes data to a file named by filename. 29 func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error { 30 f, err := NewAtomicFileWriter(filename, perm) 31 if err != nil { 32 return err 33 } 34 n, err := f.Write(data) 35 if err == nil && n < len(data) { 36 err = io.ErrShortWrite 37 } 38 if err1 := f.Close(); err == nil { 39 err = err1 40 } 41 return err 42 } 43 44 type atomicFileWriter struct { 45 f *os.File 46 fn string 47 writeErr error 48 } 49 50 func (w *atomicFileWriter) Write(dt []byte) (int, error) { 51 n, err := w.f.Write(dt) 52 if err != nil { 53 w.writeErr = err 54 } 55 return n, err 56 } 57 58 func (w *atomicFileWriter) Close() (retErr error) { 59 defer func() { 60 if retErr != nil { 61 os.Remove(w.f.Name()) 62 } 63 }() 64 if err := w.f.Sync(); err != nil { 65 w.f.Close() 66 return err 67 } 68 if err := w.f.Close(); err != nil { 69 return err 70 } 71 if w.writeErr == nil { 72 return os.Rename(w.f.Name(), w.fn) 73 } 74 return nil 75 }