diff --git a/libs/common/os.go b/libs/common/os.go index 00f4da57b..b8419764e 100644 --- a/libs/common/os.go +++ b/libs/common/os.go @@ -8,7 +8,6 @@ import ( "os" "os/exec" "os/signal" - "path/filepath" "strings" "syscall" ) @@ -124,60 +123,6 @@ func MustWriteFile(filePath string, contents []byte, mode os.FileMode) { } } -// WriteFileAtomic creates a temporary file with data and the perm given and -// swaps it atomically with filename if successful. -func WriteFileAtomic(filename string, data []byte, perm os.FileMode) error { - var ( - dir = filepath.Dir(filename) - tempFile = filepath.Join(dir, "write-file-atomic-"+RandStr(32)) - // Override in case it does exist, create in case it doesn't and force kernel - // flush, which still leaves the potential of lingering disk cache. - flag = os.O_WRONLY | os.O_CREATE | os.O_SYNC | os.O_TRUNC - ) - - f, err := os.OpenFile(tempFile, flag, perm) - if err != nil { - return err - } - // Clean up in any case. Defer stacking order is last-in-first-out. - defer os.Remove(f.Name()) - defer f.Close() - - if n, err := f.Write(data); err != nil { - return err - } else if n < len(data) { - return io.ErrShortWrite - } - // Close the file before renaming it, otherwise it will cause "The process - // cannot access the file because it is being used by another process." on windows. - f.Close() - - return os.Rename(f.Name(), filename) -} - -//-------------------------------------------------------------------------------- - -func Tempfile(prefix string) (*os.File, string) { - file, err := ioutil.TempFile("", prefix) - if err != nil { - PanicCrisis(err) - } - return file, file.Name() -} - -func Tempdir(prefix string) (*os.File, string) { - tempDir := os.TempDir() + "/" + prefix + RandStr(12) - err := EnsureDir(tempDir, 0700) - if err != nil { - panic(Fmt("Error creating temp dir: %v", err)) - } - dir, err := os.Open(tempDir) - if err != nil { - panic(Fmt("Error opening temp dir: %v", err)) - } - return dir, tempDir -} - //-------------------------------------------------------------------------------- func Prompt(prompt string, defaultValue string) (string, error) { diff --git a/libs/common/tempfile.go b/libs/common/tempfile.go new file mode 100644 index 000000000..94abd2c77 --- /dev/null +++ b/libs/common/tempfile.go @@ -0,0 +1,63 @@ +package common + +import ( + "io" + "io/ioutil" + "os" + "path/filepath" +) + +// WriteFileAtomic creates a temporary file with data and the perm given and +// swaps it atomically with filename if successful. +func WriteFileAtomic(filename string, data []byte, perm os.FileMode) error { + var ( + dir = filepath.Dir(filename) + // Create in case it doesn't exist and force kernel + // flush, which still leaves the potential of lingering disk cache. + // Never overwrites files + flag = os.O_WRONLY | os.O_CREATE | os.O_SYNC | os.O_TRUNC | os.O_EXCL + ) + + tempFile := filepath.Join(dir, "write-file-atomic-"+RandStr(32)) + f, err := os.OpenFile(tempFile, flag, perm) + if err != nil { + return err + } + // Clean up in any case. Defer stacking order is last-in-first-out. + defer os.Remove(f.Name()) + defer f.Close() + + if n, err := f.Write(data); err != nil { + return err + } else if n < len(data) { + return io.ErrShortWrite + } + // Close the file before renaming it, otherwise it will cause "The process + // cannot access the file because it is being used by another process." on windows. + f.Close() + + return os.Rename(f.Name(), filename) +} + +//-------------------------------------------------------------------------------- + +func Tempfile(prefix string) (*os.File, string) { + file, err := ioutil.TempFile("", prefix) + if err != nil { + PanicCrisis(err) + } + return file, file.Name() +} + +func Tempdir(prefix string) (*os.File, string) { + tempDir := os.TempDir() + "/" + prefix + RandStr(12) + err := EnsureDir(tempDir, 0700) + if err != nil { + panic(Fmt("Error creating temp dir: %v", err)) + } + dir, err := os.Open(tempDir) + if err != nil { + panic(Fmt("Error opening temp dir: %v", err)) + } + return dir, tempDir +}