Skip to content

Commit 29f7ebc

Browse files
dkegel-fastlydeadprogram
authored andcommitted
os: pull in os.Rename and some of its tests from upstream
Skip part of the test on Windows because of #2480 TODO: fix 2480 and unskip test TODO: pull in rest of upstream tests, fix problems they find Requested in #2109
1 parent 72e15af commit 29f7ebc

File tree

5 files changed

+127
-1
lines changed

5 files changed

+127
-1
lines changed

src/os/file_anyos.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ func Chdir(dir string) error {
4040
return nil
4141
}
4242

43+
// Rename renames (moves) oldpath to newpath.
44+
// If newpath already exists and is not a directory, Rename replaces it.
45+
// OS-specific restrictions may apply when oldpath and newpath are in different directories.
46+
// If there is an error, it will be of type *LinkError.
47+
func Rename(oldpath, newpath string) error {
48+
return rename(oldpath, newpath)
49+
}
50+
4351
// unixFilesystem is an empty handle for a Unix/Linux filesystem. All operations
4452
// are relative to the current working directory.
4553
type unixFilesystem struct {

src/os/file_unix.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ func fixLongPath(path string) string {
1818
return path
1919
}
2020

21+
func rename(oldname, newname string) error {
22+
// TODO: import rest of upstream tests, handle fancy cases
23+
err := syscall.Rename(oldname, newname)
24+
if err != nil {
25+
return &LinkError{"rename", oldname, newname, err}
26+
}
27+
return nil
28+
}
29+
2130
func Pipe() (r *File, w *File, err error) {
2231
var p [2]int
2332
err = handleSyscallError(syscall.Pipe2(p[:], syscall.O_CLOEXEC))

src/os/file_windows.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,21 @@
88
package os
99

1010
import (
11+
"internal/syscall/windows"
1112
"syscall"
1213
"unicode/utf16"
1314
)
1415

1516
type syscallFd = syscall.Handle
1617

18+
func rename(oldname, newname string) error {
19+
e := windows.Rename(fixLongPath(oldname), fixLongPath(newname))
20+
if e != nil {
21+
return &LinkError{"rename", oldname, newname, e}
22+
}
23+
return nil
24+
}
25+
1726
func Pipe() (r *File, w *File, err error) {
1827
var p [2]syscall.Handle
1928
e := handleSyscallError(syscall.Pipe(p[:]))

src/os/os_anyos_test.go

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package os_test
44

55
import (
6+
"io/ioutil"
67
. "os"
78
"path/filepath"
89
"runtime"
@@ -35,7 +36,7 @@ func TestMkdir(t *testing.T) {
3536

3637
func TestStatBadDir(t *testing.T) {
3738
if runtime.GOOS == "windows" {
38-
t.Log("TODO: TestStatBadDir fails on Windows, skipping")
39+
t.Log("TODO: TestStatBadDir: IsNotExist fails on Windows, skipping")
3940
return
4041
}
4142
dir := TempDir()
@@ -94,3 +95,88 @@ func TestRemove(t *testing.T) {
9495
t.Fatalf("Remove: %v", err)
9596
}
9697
}
98+
99+
func TestRename(t *testing.T) {
100+
// TODO: use t.TempDir()
101+
from, to := TempDir()+"/"+"TestRename-from", TempDir()+"/"+"TestRename-to"
102+
103+
file, err := Create(from)
104+
defer Remove(from) // TODO: switch to t.Tempdir, remove this line
105+
if err != nil {
106+
t.Fatalf("open %q failed: %v", from, err)
107+
}
108+
defer Remove(to) // TODO: switch to t.Tempdir, remove this line
109+
if err = file.Close(); err != nil {
110+
t.Errorf("close %q failed: %v", from, err)
111+
}
112+
err = Rename(from, to)
113+
if err != nil {
114+
t.Fatalf("rename %q, %q failed: %v", to, from, err)
115+
}
116+
_, err = Stat(to)
117+
if err != nil {
118+
t.Errorf("stat %q failed: %v", to, err)
119+
}
120+
}
121+
122+
func TestRenameOverwriteDest(t *testing.T) {
123+
from, to := TempDir()+"/"+"TestRenameOverwrite-from", TempDir()+"/"+"TestRenameOverwrite-to"
124+
125+
toData := []byte("to")
126+
fromData := []byte("from")
127+
128+
err := ioutil.WriteFile(to, toData, 0777)
129+
defer Remove(to) // TODO: switch to t.Tempdir, remove this line
130+
if err != nil {
131+
t.Fatalf("write file %q failed: %v", to, err)
132+
}
133+
134+
err = ioutil.WriteFile(from, fromData, 0777)
135+
defer Remove(from) // TODO: switch to t.Tempdir, remove this line
136+
if err != nil {
137+
t.Fatalf("write file %q failed: %v", from, err)
138+
}
139+
err = Rename(from, to)
140+
if err != nil {
141+
t.Fatalf("rename %q, %q failed: %v", to, from, err)
142+
}
143+
144+
_, err = Stat(from)
145+
if err == nil {
146+
t.Errorf("from file %q still exists", from)
147+
}
148+
if runtime.GOOS == "windows" {
149+
t.Log("TODO: TestRenameOverwriteDest: IsNotExist fails on Windows, skipping")
150+
} else if err != nil && !IsNotExist(err) {
151+
t.Fatalf("stat from: %v", err)
152+
}
153+
toFi, err := Stat(to)
154+
if err != nil {
155+
t.Fatalf("stat %q failed: %v", to, err)
156+
}
157+
if toFi.Size() != int64(len(fromData)) {
158+
t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData))
159+
}
160+
}
161+
162+
func TestRenameFailed(t *testing.T) {
163+
from, to := TempDir()+"/"+"RenameFailed-from", TempDir()+"/"+"RenameFailed-to"
164+
165+
err := Rename(from, to)
166+
switch err := err.(type) {
167+
case *LinkError:
168+
if err.Op != "rename" {
169+
t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
170+
}
171+
if err.Old != from {
172+
t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
173+
}
174+
if err.New != to {
175+
t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
176+
}
177+
case nil:
178+
t.Errorf("rename %q, %q: expected error, got nil", from, to)
179+
default:
180+
t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
181+
}
182+
}

src/syscall/syscall_libc.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ func Rmdir(path string) (err error) {
9595
return
9696
}
9797

98+
func Rename(from, to string) (err error) {
99+
fromdata := cstring(from)
100+
todata := cstring(to)
101+
fail := int(libc_rename(&fromdata[0], &todata[0]))
102+
if fail < 0 {
103+
err = getErrno()
104+
}
105+
return
106+
}
107+
98108
func Unlink(path string) (err error) {
99109
data := cstring(path)
100110
fail := int(libc_unlink(&data[0]))
@@ -270,6 +280,10 @@ func libc_mkdir(pathname *byte, mode uint32) int32
270280
//export rmdir
271281
func libc_rmdir(pathname *byte) int32
272282

283+
// int rename(const char *from, *to);
284+
//export rename
285+
func libc_rename(from, too *byte) int32
286+
273287
// int unlink(const char *pathname);
274288
//export unlink
275289
func libc_unlink(pathname *byte) int32

0 commit comments

Comments
 (0)