os: Implement and smoke test Mkdir() and Remove()
Этот коммит содержится в:
родитель
aea4f57a2b
коммит
339301b709
5 изменённых файлов: 143 добавлений и 3 удалений
1
Makefile
1
Makefile
|
@ -223,6 +223,7 @@ TEST_PACKAGES = \
|
||||||
math \
|
math \
|
||||||
math/cmplx \
|
math/cmplx \
|
||||||
net/mail \
|
net/mail \
|
||||||
|
os \
|
||||||
reflect \
|
reflect \
|
||||||
testing \
|
testing \
|
||||||
testing/iotest \
|
testing/iotest \
|
||||||
|
|
|
@ -175,6 +175,8 @@ func IsPathSeparator(c uint8) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathError records an error and the operation and file path that caused it.
|
// PathError records an error and the operation and file path that caused it.
|
||||||
|
// TODO: PathError moved to io/fs in go 1.16 and left an alias in os/errors.go.
|
||||||
|
// Do the same once we drop support for go 1.15.
|
||||||
type PathError struct {
|
type PathError struct {
|
||||||
Op string
|
Op string
|
||||||
Path string
|
Path string
|
||||||
|
|
|
@ -35,7 +35,32 @@ func (fs unixFilesystem) Mkdir(path string, perm FileMode) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs unixFilesystem) Remove(path string) error {
|
func (fs unixFilesystem) Remove(path string) error {
|
||||||
return handleSyscallError(syscall.Unlink(path))
|
// System call interface forces us to know
|
||||||
|
// whether name is a file or directory.
|
||||||
|
// Try both: it is cheaper on average than
|
||||||
|
// doing a Stat plus the right one.
|
||||||
|
e := handleSyscallError(syscall.Unlink(path))
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
e1 := handleSyscallError(syscall.Rmdir(path))
|
||||||
|
if e1 == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both failed: figure out which error to return.
|
||||||
|
// OS X and Linux differ on whether unlink(dir)
|
||||||
|
// returns EISDIR, so can't use that. However,
|
||||||
|
// both agree that rmdir(file) returns ENOTDIR,
|
||||||
|
// so we can use that to decide which error is real.
|
||||||
|
// Rmdir might also return ENOTDIR if given a bad
|
||||||
|
// file path, like /etc/passwd/foo, but in that case,
|
||||||
|
// both errors will be ENOTDIR, so it's okay to
|
||||||
|
// use the error from unlink.
|
||||||
|
if e1 != syscall.ENOTDIR {
|
||||||
|
e = e1
|
||||||
|
}
|
||||||
|
return &PathError{Op: "remove", Path: path, Err: e}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs unixFilesystem) OpenFile(path string, flag int, perm FileMode) (FileHandle, error) {
|
func (fs unixFilesystem) OpenFile(path string, flag int, perm FileMode) (FileHandle, error) {
|
||||||
|
|
81
src/os/os_unix_test.go
Обычный файл
81
src/os/os_unix_test.go
Обычный файл
|
@ -0,0 +1,81 @@
|
||||||
|
// +build darwin linux,!baremetal freebsd,!baremetal
|
||||||
|
|
||||||
|
package os_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "os"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func randomName() string {
|
||||||
|
// fastrand() does not seem available here, so fake it
|
||||||
|
ns := time.Now().Nanosecond()
|
||||||
|
pid := Getpid()
|
||||||
|
return strconv.FormatUint(uint64(ns^pid), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMkdir(t *testing.T) {
|
||||||
|
dir := "TestMkdir" + randomName()
|
||||||
|
Remove(dir)
|
||||||
|
err := Mkdir(dir, 0755)
|
||||||
|
defer Remove(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Mkdir(%s, 0755) returned %v", dir, err)
|
||||||
|
}
|
||||||
|
// tests the "directory" branch of Remove
|
||||||
|
err = Remove(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Remove(%s) returned %v", dir, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeFile(t *testing.T, fname string, flag int, text string) string {
|
||||||
|
f, err := OpenFile(fname, flag, 0666)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Open: %v", err)
|
||||||
|
}
|
||||||
|
n, err := f.WriteString(text)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("WriteString: %d, %v", n, err)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
data, err := ReadFile(f.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReadFile: %v", err)
|
||||||
|
}
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemove(t *testing.T) {
|
||||||
|
f := "TestRemove" + randomName()
|
||||||
|
|
||||||
|
err := Remove(f)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("TestRemove: remove of nonexistent file did not fail")
|
||||||
|
} else {
|
||||||
|
// FIXME: once we drop go 1.15, switch this to fs.PathError
|
||||||
|
if pe, ok := err.(*PathError); !ok {
|
||||||
|
t.Errorf("TestRemove: expected PathError, got err %q", err.Error())
|
||||||
|
} else {
|
||||||
|
if pe.Path != f {
|
||||||
|
t.Errorf("TestRemove: PathError returned path %q, expected %q", pe.Path, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: make this pass.
|
||||||
|
if !IsNotExist(err) {
|
||||||
|
t.Logf("TestRemove: TODO: expected IsNotExist(err) true, got false; err %q", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
|
||||||
|
if s != "new" {
|
||||||
|
t.Fatalf("writeFile: have %q want %q", s, "new")
|
||||||
|
}
|
||||||
|
// tests the "file" branch of Remove
|
||||||
|
err = Remove(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Remove: %v", err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,11 +51,30 @@ func Open(path string, flag int, mode uint32) (fd int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Mkdir(path string, mode uint32) (err error) {
|
func Mkdir(path string, mode uint32) (err error) {
|
||||||
return ENOSYS // TODO
|
data := cstring(path)
|
||||||
|
fail := int(libc_mkdir(&data[0], mode))
|
||||||
|
if fail < 0 {
|
||||||
|
err = getErrno()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Rmdir(path string) (err error) {
|
||||||
|
data := cstring(path)
|
||||||
|
fail := int(libc_rmdir(&data[0]))
|
||||||
|
if fail < 0 {
|
||||||
|
err = getErrno()
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func Unlink(path string) (err error) {
|
func Unlink(path string) (err error) {
|
||||||
return ENOSYS // TODO
|
data := cstring(path)
|
||||||
|
fail := int(libc_unlink(&data[0]))
|
||||||
|
if fail < 0 {
|
||||||
|
err = getErrno()
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func Kill(pid int, sig Signal) (err error) {
|
func Kill(pid int, sig Signal) (err error) {
|
||||||
|
@ -136,3 +155,15 @@ func libc_mmap(addr unsafe.Pointer, length uintptr, prot, flags, fd int32, offse
|
||||||
// int mprotect(void *addr, size_t len, int prot);
|
// int mprotect(void *addr, size_t len, int prot);
|
||||||
//export mprotect
|
//export mprotect
|
||||||
func libc_mprotect(addr unsafe.Pointer, len uintptr, prot int32) int32
|
func libc_mprotect(addr unsafe.Pointer, len uintptr, prot int32) int32
|
||||||
|
|
||||||
|
// int mkdir(const char *pathname, mode_t mode);
|
||||||
|
//export mkdir
|
||||||
|
func libc_mkdir(pathname *byte, mode uint32) int32
|
||||||
|
|
||||||
|
// int rmdir(const char *pathname);
|
||||||
|
//export rmdir
|
||||||
|
func libc_rmdir(pathname *byte) int32
|
||||||
|
|
||||||
|
// int unlink(const char *pathname);
|
||||||
|
//export unlink
|
||||||
|
func libc_unlink(pathname *byte) int32
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче