github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/osutil/fileutil.go (about)

     1  // Copyright 2015 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package osutil
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  )
    11  
    12  // CopyFile atomically copies oldFile to newFile preserving permissions and modification time.
    13  func CopyFile(oldFile, newFile string) error {
    14  	oldf, err := os.Open(oldFile)
    15  	if err != nil {
    16  		return err
    17  	}
    18  	defer oldf.Close()
    19  	stat, err := oldf.Stat()
    20  	if err != nil {
    21  		return err
    22  	}
    23  	tmpFile := newFile + ".tmp"
    24  	newf, err := os.OpenFile(tmpFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, stat.Mode()&os.ModePerm)
    25  	if err != nil {
    26  		return err
    27  	}
    28  	defer newf.Close()
    29  	_, err = io.Copy(newf, oldf)
    30  	if err != nil {
    31  		return err
    32  	}
    33  	if err := newf.Close(); err != nil {
    34  		return err
    35  	}
    36  	if err := os.Chtimes(tmpFile, stat.ModTime(), stat.ModTime()); err != nil {
    37  		return err
    38  	}
    39  	return os.Rename(tmpFile, newFile)
    40  }
    41  
    42  // Rename is similar to os.Rename but handles cross-device renaming (by copying).
    43  func Rename(oldFile, newFile string) error {
    44  	err := os.Rename(oldFile, newFile)
    45  	if err != nil {
    46  		// Can't use syscall.EXDEV because this is used in appengine app.
    47  		err = CopyFile(oldFile, newFile)
    48  		os.Remove(oldFile)
    49  	}
    50  	return err
    51  }
    52  
    53  // WriteTempFile writes data to a temp file and returns its name.
    54  func WriteTempFile(data []byte) (string, error) {
    55  	// Note: pkg/report knows about "syzkaller" prefix as it appears in crashes as process name.
    56  	f, err := os.CreateTemp("", "syzkaller")
    57  	if err != nil {
    58  		return "", fmt.Errorf("failed to create a temp file: %w", err)
    59  	}
    60  	if _, err := f.Write(data); err != nil {
    61  		f.Close()
    62  		os.Remove(f.Name())
    63  		return "", fmt.Errorf("failed to write a temp file: %w", err)
    64  	}
    65  	f.Close()
    66  	return f.Name(), nil
    67  }