github.com/lmb/consul@v1.4.1/lib/file/atomic.go (about)

     1  package file
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/hashicorp/go-uuid"
     9  )
    10  
    11  // WriteAtomic writes the given contents to a temporary file in the same
    12  // directory, does an fsync and then renames the file to its real path
    13  func WriteAtomic(path string, contents []byte) error {
    14  	uuid, err := uuid.GenerateUUID()
    15  	if err != nil {
    16  		return err
    17  	}
    18  	tempPath := fmt.Sprintf("%s-%s.tmp", path, uuid)
    19  
    20  	if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
    21  		return err
    22  	}
    23  	fh, err := os.OpenFile(tempPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
    24  	if err != nil {
    25  		return err
    26  	}
    27  	if _, err := fh.Write(contents); err != nil {
    28  		fh.Close()
    29  		os.Remove(tempPath)
    30  		return err
    31  	}
    32  	if err := fh.Sync(); err != nil {
    33  		fh.Close()
    34  		os.Remove(tempPath)
    35  		return err
    36  	}
    37  	if err := fh.Close(); err != nil {
    38  		os.Remove(tempPath)
    39  		return err
    40  	}
    41  	if err := os.Rename(tempPath, path); err != nil {
    42  		os.Remove(tempPath)
    43  		return err
    44  	}
    45  	return nil
    46  }