github.com/criteo-forks/consul@v1.4.5-criteonogrpc/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  	return WriteAtomicWithPerms(path, contents, 0700)
    15  }
    16  
    17  func WriteAtomicWithPerms(path string, contents []byte, permissions os.FileMode) error {
    18  
    19  	uuid, err := uuid.GenerateUUID()
    20  	if err != nil {
    21  		return err
    22  	}
    23  	tempPath := fmt.Sprintf("%s-%s.tmp", path, uuid)
    24  
    25  	if err := os.MkdirAll(filepath.Dir(path), permissions); err != nil {
    26  		return err
    27  	}
    28  	fh, err := os.OpenFile(tempPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
    29  	if err != nil {
    30  		return err
    31  	}
    32  	if _, err := fh.Write(contents); err != nil {
    33  		fh.Close()
    34  		os.Remove(tempPath)
    35  		return err
    36  	}
    37  	if err := fh.Sync(); err != nil {
    38  		fh.Close()
    39  		os.Remove(tempPath)
    40  		return err
    41  	}
    42  	if err := fh.Close(); err != nil {
    43  		os.Remove(tempPath)
    44  		return err
    45  	}
    46  	if err := os.Rename(tempPath, path); err != nil {
    47  		os.Remove(tempPath)
    48  		return err
    49  	}
    50  	return nil
    51  }