aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/osutil/fileutil.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/osutil/fileutil.go')
-rw-r--r--pkg/osutil/fileutil.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/pkg/osutil/fileutil.go b/pkg/osutil/fileutil.go
new file mode 100644
index 000000000..801453326
--- /dev/null
+++ b/pkg/osutil/fileutil.go
@@ -0,0 +1,107 @@
+// Copyright 2015 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package osutil
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strconv"
+ "syscall"
+)
+
+// CopyFile atomically copies oldFile to newFile preserving permissions and modification time.
+func CopyFile(oldFile, newFile string) error {
+ oldf, err := os.Open(oldFile)
+ if err != nil {
+ return err
+ }
+ defer oldf.Close()
+ stat, err := oldf.Stat()
+ if err != nil {
+ return err
+ }
+ tmpFile := newFile + ".tmp"
+ newf, err := os.OpenFile(tmpFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, stat.Mode()&os.ModePerm)
+ if err != nil {
+ return err
+ }
+ defer newf.Close()
+ _, err = io.Copy(newf, oldf)
+ if err != nil {
+ return err
+ }
+ if err := newf.Close(); err != nil {
+ return err
+ }
+ if err := os.Chtimes(tmpFile, stat.ModTime(), stat.ModTime()); err != nil {
+ return err
+ }
+ return os.Rename(tmpFile, newFile)
+}
+
+// WriteTempFile writes data to a temp file and returns its name.
+func WriteTempFile(data []byte) (string, error) {
+ f, err := ioutil.TempFile("", "syzkaller")
+ if err != nil {
+ return "", fmt.Errorf("failed to create a temp file: %v", err)
+ }
+ if _, err := f.Write(data); err != nil {
+ f.Close()
+ os.Remove(f.Name())
+ return "", fmt.Errorf("failed to write a temp file: %v", err)
+ }
+ f.Close()
+ return f.Name(), nil
+}
+
+// ProcessTempDir creates a new temp dir in where and returns its path and an unique index.
+// It also cleans up old, unused temp dirs after dead processes.
+func ProcessTempDir(where string) (string, error) {
+ lk := filepath.Join(where, "instance-lock")
+ lkf, err := syscall.Open(lk, syscall.O_RDWR|syscall.O_CREAT, DefaultFilePerm)
+ if err != nil {
+ return "", err
+ }
+ defer syscall.Close(lkf)
+ if err := syscall.Flock(lkf, syscall.LOCK_EX); err != nil {
+ return "", err
+ }
+ defer syscall.Flock(lkf, syscall.LOCK_UN)
+
+ for i := 0; i < 1e3; i++ {
+ path := filepath.Join(where, fmt.Sprintf("instance-%v", i))
+ pidfile := filepath.Join(path, ".pid")
+ err := os.Mkdir(path, DefaultDirPerm)
+ if os.IsExist(err) {
+ // Try to clean up.
+ data, err := ioutil.ReadFile(pidfile)
+ if err == nil && len(data) > 0 {
+ pid, err := strconv.Atoi(string(data))
+ if err == nil && pid > 1 {
+ if err := syscall.Kill(pid, 0); err == syscall.ESRCH {
+ if os.Remove(pidfile) == nil {
+ if os.RemoveAll(path) == nil {
+ i--
+ continue
+ }
+ }
+ }
+ }
+ }
+ // If err != nil, assume that the pid file is not created yet.
+ continue
+ }
+ if err != nil {
+ return "", err
+ }
+ if err := WriteFile(pidfile, []byte(strconv.Itoa(syscall.Getpid()))); err != nil {
+ return "", err
+ }
+ return path, nil
+ }
+ return "", fmt.Errorf("too many live instances")
+}