| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- // Package atomicfile contains code related to writing to filesystems
- // atomically.
- //
- // This package should be considered internal; its API is not stable.
- package atomicfile // import "tailscale.com/atomicfile"
- import (
- "fmt"
- "os"
- "path/filepath"
- "runtime"
- )
- // WriteFile writes data to filename+some suffix, then renames it into filename.
- // The perm argument is ignored on Windows, but if the target filename already
- // exists then the target file's attributes and ACLs are preserved. If the target
- // filename already exists but is not a regular file, WriteFile returns an error.
- func WriteFile(filename string, data []byte, perm os.FileMode) (err error) {
- fi, err := os.Stat(filename)
- if err == nil && !fi.Mode().IsRegular() {
- return fmt.Errorf("%s already exists and is not a regular file", filename)
- }
- f, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename)+".tmp")
- if err != nil {
- return err
- }
- tmpName := f.Name()
- defer func() {
- if err != nil {
- f.Close()
- os.Remove(tmpName)
- }
- }()
- if _, err := f.Write(data); err != nil {
- return err
- }
- if runtime.GOOS != "windows" {
- if err := f.Chmod(perm); err != nil {
- return err
- }
- }
- if err := f.Sync(); err != nil {
- return err
- }
- if err := f.Close(); err != nil {
- return err
- }
- return Rename(tmpName, filename)
- }
- // Rename srcFile to dstFile, similar to [os.Rename] but preserving file
- // attributes and ACLs on Windows.
- func Rename(srcFile, dstFile string) error { return rename(srcFile, dstFile) }
|