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  }