github.com/brahmaroutu/docker@v1.2.1-0.20160809185609-eb28dde01f16/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 19 abspath, err := filepath.Abs(filename) 20 if err != nil { 21 return nil, err 22 } 23 return &atomicFileWriter{ 24 f: f, 25 fn: abspath, 26 perm: perm, 27 }, nil 28 } 29 30 // AtomicWriteFile atomically writes data to a file named by filename. 31 func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error { 32 f, err := NewAtomicFileWriter(filename, perm) 33 if err != nil { 34 return err 35 } 36 n, err := f.Write(data) 37 if err == nil && n < len(data) { 38 err = io.ErrShortWrite 39 f.(*atomicFileWriter).writeErr = err 40 } 41 if err1 := f.Close(); err == nil { 42 err = err1 43 } 44 return err 45 } 46 47 type atomicFileWriter struct { 48 f *os.File 49 fn string 50 writeErr error 51 perm os.FileMode 52 } 53 54 func (w *atomicFileWriter) Write(dt []byte) (int, error) { 55 n, err := w.f.Write(dt) 56 if err != nil { 57 w.writeErr = err 58 } 59 return n, err 60 } 61 62 func (w *atomicFileWriter) Close() (retErr error) { 63 defer func() { 64 if retErr != nil || w.writeErr != nil { 65 os.Remove(w.f.Name()) 66 } 67 }() 68 if err := w.f.Sync(); err != nil { 69 w.f.Close() 70 return err 71 } 72 if err := w.f.Close(); err != nil { 73 return err 74 } 75 if err := os.Chmod(w.f.Name(), w.perm); err != nil { 76 return err 77 } 78 if w.writeErr == nil { 79 return os.Rename(w.f.Name(), w.fn) 80 } 81 return nil 82 }