diff --git a/src/cmd/go/internal/renameio/renameio.go b/src/cmd/go/internal/renameio/renameio.go index 8f59e1a577..3f3f1708fa 100644 --- a/src/cmd/go/internal/renameio/renameio.go +++ b/src/cmd/go/internal/renameio/renameio.go @@ -11,6 +11,9 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" + "strings" + "time" ) const patternSuffix = "*.tmp" @@ -59,5 +62,22 @@ func WriteToFile(filename string, data io.Reader) (err error) { if err := f.Close(); err != nil { return err } - return os.Rename(f.Name(), filename) + + var start time.Time + for { + err := os.Rename(f.Name(), filename) + if err == nil || runtime.GOOS != "windows" || !strings.HasSuffix(err.Error(), "Access is denied.") { + return err + } + + // Windows seems to occasionally trigger spurious "Access is denied" errors + // here (see golang.org/issue/31247). We're not sure why. It's probably + // worth a little extra latency to avoid propagating the spurious errors. + if start.IsZero() { + start = time.Now() + } else if time.Since(start) >= 500*time.Millisecond { + return err + } + time.Sleep(5 * time.Millisecond) + } }