...

Source file src/github.com/rogpeppe/go-internal/renameio/renameio.go

Documentation: github.com/rogpeppe/go-internal/renameio

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package renameio writes files atomically by renaming temporary files.
     6  //
     7  // Deprecated: Use [github.com/google/renameio/v2] instead.
     8  package renameio
     9  
    10  import (
    11  	"bytes"
    12  	"io"
    13  	"io/ioutil"
    14  	"os"
    15  	"path/filepath"
    16  )
    17  
    18  const patternSuffix = "*.tmp"
    19  
    20  // Pattern returns a glob pattern that matches the unrenamed temporary files
    21  // created when writing to filename.
    22  func Pattern(filename string) string {
    23  	return filepath.Join(filepath.Dir(filename), filepath.Base(filename)+patternSuffix)
    24  }
    25  
    26  // WriteFile is like ioutil.WriteFile, but first writes data to an arbitrary
    27  // file in the same directory as filename, then renames it atomically to the
    28  // final name.
    29  //
    30  // That ensures that the final location, if it exists, is always a complete file.
    31  func WriteFile(filename string, data []byte) (err error) {
    32  	return WriteToFile(filename, bytes.NewReader(data))
    33  }
    34  
    35  // WriteToFile is a variant of WriteFile that accepts the data as an io.Reader
    36  // instead of a slice.
    37  func WriteToFile(filename string, data io.Reader) (err error) {
    38  	f, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)+patternSuffix)
    39  	if err != nil {
    40  		return err
    41  	}
    42  	defer func() {
    43  		// Only call os.Remove on f.Name() if we failed to rename it: otherwise,
    44  		// some other process may have created a new file with the same name after
    45  		// that.
    46  		if err != nil {
    47  			f.Close()
    48  			os.Remove(f.Name())
    49  		}
    50  	}()
    51  
    52  	if _, err := io.Copy(f, data); err != nil {
    53  		return err
    54  	}
    55  	// Sync the file before renaming it: otherwise, after a crash the reader may
    56  	// observe a 0-length file instead of the actual contents.
    57  	// See https://golang.org/issue/22397#issuecomment-380831736.
    58  	if err := f.Sync(); err != nil {
    59  		return err
    60  	}
    61  	if err := f.Close(); err != nil {
    62  		return err
    63  	}
    64  	return os.Rename(f.Name(), filename)
    65  }
    66  

View as plain text