os: implement os.Symlink and os.Readlink
Этот коммит содержится в:
родитель
db0efc52c7
коммит
57b8f7e667
6 изменённых файлов: 183 добавлений и 11 удалений
|
@ -38,6 +38,15 @@ func Mkdir(path string, perm FileMode) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Many functions in package syscall return a count of -1 instead of 0.
|
||||
// Using fixCount(call()) instead of call() corrects the count.
|
||||
func fixCount(n int, err error) (int, error) {
|
||||
if n < 0 {
|
||||
n = 0
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Remove removes a file or (empty) directory. If the operation fails, it will
|
||||
// return an error of type *PathError.
|
||||
func Remove(path string) error {
|
||||
|
@ -52,11 +61,6 @@ func Remove(path string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Symlink is a stub, it is not implemented.
|
||||
func Symlink(oldname, newname string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
// RemoveAll is a stub, it is not implemented.
|
||||
func RemoveAll(path string) error {
|
||||
return ErrNotImplemented
|
||||
|
@ -257,11 +261,6 @@ func Getwd() (string, error) {
|
|||
return syscall.Getwd()
|
||||
}
|
||||
|
||||
// Readlink is a stub (for now), always returning the string it was given
|
||||
func Readlink(name string) (string, error) {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// TempDir returns the default directory to use for temporary files.
|
||||
//
|
||||
// On Unix systems, it returns $TMPDIR if non-empty, else /tmp.
|
||||
|
|
|
@ -52,6 +52,44 @@ func tempDir() string {
|
|||
return dir
|
||||
}
|
||||
|
||||
// Symlink creates newname as a symbolic link to oldname.
|
||||
// On Windows, a symlink to a non-existent oldname creates a file symlink;
|
||||
// if oldname is later created as a directory the symlink will not work.
|
||||
// If there is an error, it will be of type *LinkError.
|
||||
func Symlink(oldname, newname string) error {
|
||||
e := ignoringEINTR(func() error {
|
||||
return syscall.Symlink(oldname, newname)
|
||||
})
|
||||
if e != nil {
|
||||
return &LinkError{"symlink", oldname, newname, e}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Readlink returns the destination of the named symbolic link.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Readlink(name string) (string, error) {
|
||||
for len := 128; ; len *= 2 {
|
||||
b := make([]byte, len)
|
||||
var (
|
||||
n int
|
||||
e error
|
||||
)
|
||||
for {
|
||||
n, e = fixCount(syscall.Readlink(name, b))
|
||||
if e != syscall.EINTR {
|
||||
break
|
||||
}
|
||||
}
|
||||
if e != nil {
|
||||
return "", &PathError{Op: "readlink", Path: name, Err: e}
|
||||
}
|
||||
if n < len {
|
||||
return string(b[0:n]), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReadAt reads up to len(b) bytes from the File starting at the given absolute offset.
|
||||
// It returns the number of bytes read and any error encountered, possibly io.EOF.
|
||||
// At end of file, Pread returns 0, io.EOF.
|
||||
|
|
|
@ -15,6 +15,16 @@ import (
|
|||
|
||||
type syscallFd = syscall.Handle
|
||||
|
||||
// Symlink is a stub, it is not implemented.
|
||||
func Symlink(oldname, newname string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
// Readlink is a stub (for now), always returning the string it was given
|
||||
func Readlink(name string) (string, error) {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func rename(oldname, newname string) error {
|
||||
e := windows.Rename(fixLongPath(oldname), fixLongPath(newname))
|
||||
if e != nil {
|
||||
|
|
|
@ -96,6 +96,28 @@ func TestRemove(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// chtmpdir changes the working directory to a new temporary directory and
|
||||
// provides a cleanup function.
|
||||
func chtmpdir(t *testing.T) func() {
|
||||
oldwd, err := Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("chtmpdir: %v", err)
|
||||
}
|
||||
d, err := MkdirTemp("", "test")
|
||||
if err != nil {
|
||||
t.Fatalf("chtmpdir: %v", err)
|
||||
}
|
||||
if err := Chdir(d); err != nil {
|
||||
t.Fatalf("chtmpdir: %v", err)
|
||||
}
|
||||
return func() {
|
||||
if err := Chdir(oldwd); err != nil {
|
||||
t.Fatalf("chtmpdir: %v", err)
|
||||
}
|
||||
RemoveAll(d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRename(t *testing.T) {
|
||||
// TODO: use t.TempDir()
|
||||
from, to := TempDir()+"/"+"TestRename-from", TempDir()+"/"+"TestRename-to"
|
||||
|
|
75
src/os/os_symlink_test.go
Обычный файл
75
src/os/os_symlink_test.go
Обычный файл
|
@ -0,0 +1,75 @@
|
|||
// +build !windows,!baremetal,!js,!wasi
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package os_test
|
||||
|
||||
import (
|
||||
. "os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TODO: Move this back into os_anyos_test.go when wasi supports symlink
|
||||
|
||||
func TestSymlink(t *testing.T) {
|
||||
//testenv.MustHaveSymlink(t)
|
||||
|
||||
defer chtmpdir(t)()
|
||||
from, to := "symlinktestfrom", "symlinktestto"
|
||||
file, err := Create(to)
|
||||
if err != nil {
|
||||
t.Fatalf("Create(%q) failed: %v", to, err)
|
||||
}
|
||||
if err = file.Close(); err != nil {
|
||||
t.Errorf("Close(%q) failed: %v", to, err)
|
||||
}
|
||||
err = Symlink(to, from)
|
||||
if err != nil {
|
||||
t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err)
|
||||
}
|
||||
tostat, err := Lstat(to)
|
||||
if err != nil {
|
||||
t.Fatalf("Lstat(%q) failed: %v", to, err)
|
||||
}
|
||||
if tostat.Mode()&ModeSymlink != 0 {
|
||||
t.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to, tostat.Mode()&ModeSymlink)
|
||||
}
|
||||
fromstat, err := Stat(from)
|
||||
if err != nil {
|
||||
t.Fatalf("Stat(%q) failed: %v", from, err)
|
||||
}
|
||||
if !SameFile(tostat, fromstat) {
|
||||
t.Errorf("Symlink(%q, %q) did not create symlink", to, from)
|
||||
}
|
||||
fromstat, err = Lstat(from)
|
||||
if err != nil {
|
||||
t.Fatalf("Lstat(%q) failed: %v", from, err)
|
||||
}
|
||||
if fromstat.Mode()&ModeSymlink == 0 {
|
||||
t.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from, ModeSymlink)
|
||||
}
|
||||
fromstat, err = Stat(from)
|
||||
if err != nil {
|
||||
t.Fatalf("Stat(%q) failed: %v", from, err)
|
||||
}
|
||||
if fromstat.Name() != from {
|
||||
t.Errorf("Stat(%q).Name() = %q, want %q", from, fromstat.Name(), from)
|
||||
}
|
||||
if fromstat.Mode()&ModeSymlink != 0 {
|
||||
t.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from, fromstat.Mode()&ModeSymlink)
|
||||
}
|
||||
s, err := Readlink(from)
|
||||
if err != nil {
|
||||
t.Fatalf("Readlink(%q) failed: %v", from, err)
|
||||
}
|
||||
if s != to {
|
||||
t.Fatalf("Readlink(%q) = %q, want %q", from, s, to)
|
||||
}
|
||||
file, err = Open(from)
|
||||
if err != nil {
|
||||
t.Fatalf("Open(%q) failed: %v", from, err)
|
||||
}
|
||||
file.Close()
|
||||
}
|
|
@ -63,6 +63,16 @@ func Open(path string, flag int, mode uint32) (fd int, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func Readlink(path string, p []byte) (n int, err error) {
|
||||
data := cstring(path)
|
||||
buf, count := splitSlice(p)
|
||||
n = libc_readlink(&data[0], buf, uint(count))
|
||||
if n < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Chdir(path string) (err error) {
|
||||
data := cstring(path)
|
||||
fail := int(libc_chdir(&data[0]))
|
||||
|
@ -109,6 +119,16 @@ func Rename(from, to string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func Symlink(from, to string) (err error) {
|
||||
fromdata := cstring(from)
|
||||
todata := cstring(to)
|
||||
fail := int(libc_symlink(&fromdata[0], &todata[0]))
|
||||
if fail < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Unlink(path string) (err error) {
|
||||
data := cstring(path)
|
||||
fail := int(libc_unlink(&data[0]))
|
||||
|
@ -303,7 +323,15 @@ func libc_rmdir(pathname *byte) int32
|
|||
|
||||
// int rename(const char *from, *to);
|
||||
//export rename
|
||||
func libc_rename(from, too *byte) int32
|
||||
func libc_rename(from, to *byte) int32
|
||||
|
||||
// int symlink(const char *from, *to);
|
||||
//export symlink
|
||||
func libc_symlink(from, to *byte) int32
|
||||
|
||||
// ssize_t readlink(const char *path, void *buf, size_t count);
|
||||
//export readlink
|
||||
func libc_readlink(path *byte, buf *byte, count uint) int
|
||||
|
||||
// int unlink(const char *pathname);
|
||||
//export unlink
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче