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 }