From a9cc88c19f0c8907d7696b47a2b3b251a2ca06df Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 17 Dec 2018 16:56:39 +0100 Subject: pkg/osutil: provide better Rename os.Rename fails for cross-device renaming (e.g. to/from tmpfs). This is quite unpleasant. Provide own version that falls back to copying. --- pkg/build/akaros.go | 2 +- pkg/build/linux.go | 2 +- pkg/db/db.go | 2 +- pkg/osutil/fileutil.go | 10 ++++++++++ pkg/vcs/fuchsia.go | 2 +- syz-ci/manager.go | 2 +- syz-ci/managercmd.go | 2 +- tools/syz-benchcmp/benchcmp.go | 4 +++- tools/syz-fmt/syz-fmt.go | 3 ++- vm/kvm/kvm.go | 2 +- 10 files changed, 22 insertions(+), 9 deletions(-) diff --git a/pkg/build/akaros.go b/pkg/build/akaros.go index 6ee3d774b..60750028f 100644 --- a/pkg/build/akaros.go +++ b/pkg/build/akaros.go @@ -52,7 +52,7 @@ func (ctx akaros) build(targetArch, vmType, kernelDir, outputDir, compiler, user return err } targetKey := filepath.Join(kernelDir, "kern", "kfs", ".ssh", "authorized_keys") - if err := os.Rename(sshkeyPub, targetKey); err != nil { + if err := osutil.Rename(sshkeyPub, targetKey); err != nil { return err } const init = `#!/bin/bash diff --git a/pkg/build/linux.go b/pkg/build/linux.go index f2bc4e0fe..dbe9cfbb7 100644 --- a/pkg/build/linux.go +++ b/pkg/build/linux.go @@ -71,7 +71,7 @@ func (linux) buildKernel(kernelDir, outputDir, compiler string, config []byte) e } vmlinux := filepath.Join(kernelDir, "vmlinux") outputVmlinux := filepath.Join(outputDir, "obj", "vmlinux") - if err := os.Rename(vmlinux, outputVmlinux); err != nil { + if err := osutil.Rename(vmlinux, outputVmlinux); err != nil { return fmt.Errorf("failed to rename vmlinux: %v", err) } return nil diff --git a/pkg/db/db.go b/pkg/db/db.go index fde371d90..e3492031b 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -118,7 +118,7 @@ func (db *DB) compact() error { return err } f.Close() - if err := os.Rename(f.Name(), db.filename); err != nil { + if err := osutil.Rename(f.Name(), db.filename); err != nil { return err } db.uncompacted = len(db.Records) diff --git a/pkg/osutil/fileutil.go b/pkg/osutil/fileutil.go index 3e107828f..0b09ff0b4 100644 --- a/pkg/osutil/fileutil.go +++ b/pkg/osutil/fileutil.go @@ -40,6 +40,16 @@ func CopyFile(oldFile, newFile string) error { return os.Rename(tmpFile, newFile) } +// Rename is similar to os.Rename but handles cross-device renaming (by copying). +func Rename(oldFile, newFile string) error { + err := os.Rename(oldFile, newFile) + if err != nil { + // Can't use syscall.EXDEV because this is used in appengine app. + return CopyFile(oldFile, newFile) + } + return err +} + // WriteTempFile writes data to a temp file and returns its name. func WriteTempFile(data []byte) (string, error) { // Note: pkg/report knows about "syzkaller" prefix as it appears in crashes as process name. diff --git a/pkg/vcs/fuchsia.go b/pkg/vcs/fuchsia.go index 354be6c8d..f9a027f67 100644 --- a/pkg/vcs/fuchsia.go +++ b/pkg/vcs/fuchsia.go @@ -56,7 +56,7 @@ func (ctx *fuchsia) initRepo() error { if _, err := runSandboxed(tmpDir, "bash", "-c", cmd); err != nil { return err } - return os.Rename(filepath.Join(tmpDir, "fuchsia"), ctx.dir) + return osutil.Rename(filepath.Join(tmpDir, "fuchsia"), ctx.dir) } func (ctx *fuchsia) CheckoutBranch(repo, branch string) (*Commit, error) { diff --git a/syz-ci/manager.go b/syz-ci/manager.go index 3401daa4b..a227acd28 100644 --- a/syz-ci/manager.go +++ b/syz-ci/manager.go @@ -331,7 +331,7 @@ func (mgr *Manager) build(kernelCommit *vcs.Commit) error { if err := os.RemoveAll(mgr.latestDir); err != nil { return fmt.Errorf("failed to remove latest dir: %v", err) } - return os.Rename(tmpDir, mgr.latestDir) + return osutil.Rename(tmpDir, mgr.latestDir) } func (mgr *Manager) restartManager() { diff --git a/syz-ci/managercmd.go b/syz-ci/managercmd.go index 74f99307f..eee09d151 100644 --- a/syz-ci/managercmd.go +++ b/syz-ci/managercmd.go @@ -74,7 +74,7 @@ func (mc *ManagerCmd) loop() { // don't restart too frequently (in case it instantly exits with an error) if time.Since(started) > restartPeriod { started = time.Now() - os.Rename(mc.log, mc.log+".old") + osutil.Rename(mc.log, mc.log+".old") logfile, err := os.Create(mc.log) if err != nil { mc.errorf("failed to create manager log: %v", err) diff --git a/tools/syz-benchcmp/benchcmp.go b/tools/syz-benchcmp/benchcmp.go index b34acafd7..387feb485 100644 --- a/tools/syz-benchcmp/benchcmp.go +++ b/tools/syz-benchcmp/benchcmp.go @@ -18,6 +18,8 @@ import ( "os/exec" "path/filepath" "sort" + + "github.com/google/syzkaller/pkg/osutil" ) var ( @@ -190,7 +192,7 @@ func display(graphs []*Graph) { } outf.Close() name := outf.Name() + ".html" - if err := os.Rename(outf.Name(), name); err != nil { + if err := osutil.Rename(outf.Name(), name); err != nil { failf("failed to rename file: %v", err) } if err := exec.Command("xdg-open", name).Start(); err != nil { diff --git a/tools/syz-fmt/syz-fmt.go b/tools/syz-fmt/syz-fmt.go index 3367a4344..76d6a8eae 100644 --- a/tools/syz-fmt/syz-fmt.go +++ b/tools/syz-fmt/syz-fmt.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/google/syzkaller/pkg/ast" + "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/sys/targets" ) @@ -67,7 +68,7 @@ func processFile(file string, mode os.FileMode) { return } fmt.Printf("reformatting %v\n", file) - if err := os.Rename(file, file+"~"); err != nil { + if err := osutil.Rename(file, file+"~"); err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } diff --git a/vm/kvm/kvm.go b/vm/kvm/kvm.go index a12db5bf8..e7948ab02 100644 --- a/vm/kvm/kvm.go +++ b/vm/kvm/kvm.go @@ -241,7 +241,7 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin if err := osutil.WriteExecFile(tmpFile, []byte(command)); err != nil { return nil, nil, err } - if err := os.Rename(tmpFile, cmdFile); err != nil { + if err := osutil.Rename(tmpFile, cmdFile); err != nil { return nil, nil, err } -- cgit mrf-deployment