From 0f0a51f1d12bb009034a38c69aa786ba62ca41e2 Mon Sep 17 00:00:00 2001
From: Alexander Menzhinsky <amenzhinsky@gmail.com>
Date: Thu, 13 Apr 2017 11:23:35 -0500
Subject: [PATCH] os: lstat oldname before renaming

Fixes #19647

Change-Id: Ife4f98cf2c55ee9490843797213dae2f2647b0a3
Reviewed-on: https://go-review.googlesource.com/40577
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
---
 src/os/file_unix.go | 15 ++++++++++++---
 src/os/os_test.go   | 12 ++++++++++++
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index 86271d53e8..f790b6e910 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -20,11 +20,20 @@ func fixLongPath(path string) string {
 func rename(oldname, newname string) error {
 	fi, err := Lstat(newname)
 	if err == nil && fi.IsDir() {
+		// if we cannot stat oldname we should
+		// return that error in favor of EEXIST
+		fi, err = Lstat(oldname)
+		if err != nil {
+			if pErr, ok := err.(*PathError); ok {
+				err = pErr.Err
+			}
+			return &LinkError{"rename", oldname, newname, err}
+		}
 		return &LinkError{"rename", oldname, newname, syscall.EEXIST}
 	}
-	e := syscall.Rename(oldname, newname)
-	if e != nil {
-		return &LinkError{"rename", oldname, newname, e}
+	err = syscall.Rename(oldname, newname)
+	if err != nil {
+		return &LinkError{"rename", oldname, newname, err}
 	}
 	return nil
 }
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 8e2cd14ddf..22777aef9f 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -886,6 +886,18 @@ func TestRenameFailed(t *testing.T) {
 	}
 }
 
+func TestRenameNotExisting(t *testing.T) {
+	defer chtmpdir(t)()
+	from, to := "doesnt-exist", "dest"
+
+	Mkdir(to, 0777)
+	defer Remove(to)
+
+	if err := Rename(from, to); !IsNotExist(err) {
+		t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err)
+	}
+}
+
 func TestRenameToDirFailed(t *testing.T) {
 	defer chtmpdir(t)()
 	from, to := "renamefrom", "renameto"
-- 
2.30.9