os: Drop support for go 1.15
1.15 specific files deleted. 1.16 specific files folded carefully into generic files, with goal of reducing diff with upstream. Follows upstream 1.16 in making PathError etc. be aliases for the same errors in io/fs. This fixes #2817 and lets us add io/ioutil to "make test-tinygo" on linux and mac.
Этот коммит содержится в:
родитель
db389ba443
коммит
e87cd23e87
15 изменённых файлов: 232 добавлений и 335 удалений
|
@ -102,9 +102,9 @@ commands:
|
|||
- run: make fmt-check
|
||||
|
||||
jobs:
|
||||
test-llvm11-go115:
|
||||
test-llvm11-go116:
|
||||
docker:
|
||||
- image: circleci/golang:1.15-buster
|
||||
- image: circleci/golang:1.16-buster
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "11"
|
||||
|
@ -118,5 +118,5 @@ jobs:
|
|||
workflows:
|
||||
test-all:
|
||||
jobs:
|
||||
- test-llvm11-go115
|
||||
- test-llvm11-go116
|
||||
- test-llvm12-go117
|
||||
|
|
|
@ -18,7 +18,7 @@ tarball. If you want to help with development of TinyGo itself, you should follo
|
|||
LLVM, Clang and LLD are quite light on dependencies, requiring only standard
|
||||
build tools to be built. Go is of course necessary to build TinyGo itself.
|
||||
|
||||
* Go (1.15+)
|
||||
* Go (1.16+)
|
||||
* Standard build tools (gcc/clang)
|
||||
* git
|
||||
* CMake
|
||||
|
|
1
Makefile
1
Makefile
|
@ -300,6 +300,7 @@ TEST_PACKAGES_LINUX := \
|
|||
debug/dwarf \
|
||||
debug/plan9obj \
|
||||
io/fs \
|
||||
io/ioutil \
|
||||
testing/fstest
|
||||
|
||||
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
|
||||
|
|
|
@ -33,8 +33,8 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
||||
}
|
||||
if major != 1 || minor < 15 || minor > 18 {
|
||||
return nil, fmt.Errorf("requires go version 1.15 through 1.18, got go%d.%d", major, minor)
|
||||
if major != 1 || minor < 16 || minor > 18 {
|
||||
return nil, fmt.Errorf("requires go version 1.16 through 1.18, got go%d.%d", major, minor)
|
||||
}
|
||||
|
||||
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
|||
module github.com/tinygo-org/tinygo
|
||||
|
||||
go 1.15
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
// Copyright 2016 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.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build (go1.16 && baremetal) || (go1.16 && js) || (go1.16 && wasi) || (go1.16 && windows)
|
||||
// +build go1.16,baremetal go1.16,js go1.16,wasi go1.16,windows
|
||||
//go:build baremetal || js || wasi || windows
|
||||
// +build baremetal js wasi windows
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
//go:build !go1.16
|
||||
// +build !go1.16
|
||||
|
||||
// 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
|
||||
|
||||
func (f *File) Readdirnames(n int) (names []string, err error) {
|
||||
return nil, ErrInvalid
|
||||
}
|
|
@ -1,21 +1,32 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Portable analogs of some common system call errors.
|
||||
//
|
||||
// Errors returned from this package may be tested against these errors
|
||||
// with errors.Is.
|
||||
var (
|
||||
ErrInvalid = errors.New("invalid argument")
|
||||
ErrPermission = errors.New("permission denied")
|
||||
ErrClosed = errors.New("file already closed")
|
||||
// ErrInvalid indicates an invalid argument.
|
||||
// Methods on File will return this error when the receiver is nil.
|
||||
ErrInvalid = fs.ErrInvalid // "invalid argument"
|
||||
|
||||
ErrPermission = fs.ErrPermission // "permission denied"
|
||||
ErrExist = fs.ErrExist // "file already exists"
|
||||
ErrNotExist = fs.ErrNotExist // "file does not exist"
|
||||
ErrClosed = fs.ErrClosed // "file already closed"
|
||||
|
||||
// Portable analogs of some common system call errors.
|
||||
// Note that these are exported for use in the Filesystem interface.
|
||||
ErrUnsupported = errors.New("operation not supported")
|
||||
ErrNotImplemented = errors.New("operation not implemented")
|
||||
ErrNotExist = errors.New("file not found")
|
||||
ErrExist = errors.New("file exists")
|
||||
)
|
||||
|
||||
// The following code is copied from the official implementation.
|
||||
|
@ -46,6 +57,9 @@ func NewSyscallError(syscall string, err error) error {
|
|||
return &SyscallError{syscall, err}
|
||||
}
|
||||
|
||||
// PathError records an error and the operation and file path that caused it.
|
||||
type PathError = fs.PathError
|
||||
|
||||
// SyscallError records an error from a specific system call.
|
||||
type SyscallError struct {
|
||||
Syscall string
|
||||
|
|
161
src/os/file.go
161
src/os/file.go
|
@ -12,6 +12,7 @@ package os
|
|||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
@ -200,23 +201,6 @@ func (f *File) Truncate(size int64) error {
|
|||
return &PathError{"truncate", f.name, ErrNotImplemented}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
Op string
|
||||
Path string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *PathError) Error() string {
|
||||
return e.Op + " " + e.Path + ": " + e.Err.Error()
|
||||
}
|
||||
|
||||
func (e *PathError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// LinkError records an error during a link or symlink or rename system call and
|
||||
// the paths that caused it.
|
||||
type LinkError struct {
|
||||
|
@ -286,3 +270,146 @@ func UserHomeDir() (string, error) {
|
|||
}
|
||||
return "", errors.New(enverr + " is not defined")
|
||||
}
|
||||
|
||||
type (
|
||||
FileMode = fs.FileMode
|
||||
FileInfo = fs.FileInfo
|
||||
)
|
||||
|
||||
// The followings are copied from Go 1.16 or 1.17 official implementation:
|
||||
// https://github.com/golang/go/blob/go1.16/src/os/file.go
|
||||
|
||||
// DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir.
|
||||
//
|
||||
// Note that DirFS("/prefix") only guarantees that the Open calls it makes to the
|
||||
// operating system will begin with "/prefix": DirFS("/prefix").Open("file") is the
|
||||
// same as os.Open("/prefix/file"). So if /prefix/file is a symbolic link pointing outside
|
||||
// the /prefix tree, then using DirFS does not stop the access any more than using
|
||||
// os.Open does. DirFS is therefore not a general substitute for a chroot-style security
|
||||
// mechanism when the directory tree contains arbitrary content.
|
||||
func DirFS(dir string) fs.FS {
|
||||
return dirFS(dir)
|
||||
}
|
||||
|
||||
func containsAny(s, chars string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
for j := 0; j < len(chars); j++ {
|
||||
if s[i] == chars[j] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type dirFS string
|
||||
|
||||
func (dir dirFS) Open(name string) (fs.File, error) {
|
||||
if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
|
||||
return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid}
|
||||
}
|
||||
f, err := Open(string(dir) + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err // nil fs.File
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (dir dirFS) Stat(name string) (fs.FileInfo, error) {
|
||||
if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
|
||||
return nil, &PathError{Op: "stat", Path: name, Err: ErrInvalid}
|
||||
}
|
||||
f, err := Stat(string(dir) + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// ReadFile reads the named file and returns the contents.
|
||||
// A successful call returns err == nil, not err == EOF.
|
||||
// Because ReadFile reads the whole file, it does not treat an EOF from Read
|
||||
// as an error to be reported.
|
||||
func ReadFile(name string) ([]byte, error) {
|
||||
f, err := Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var size int
|
||||
if info, err := f.Stat(); err == nil {
|
||||
size64 := info.Size()
|
||||
if int64(int(size64)) == size64 {
|
||||
size = int(size64)
|
||||
}
|
||||
}
|
||||
size++ // one byte for final read at EOF
|
||||
|
||||
// If a file claims a small size, read at least 512 bytes.
|
||||
// In particular, files in Linux's /proc claim size 0 but
|
||||
// then do not work right if read in small pieces,
|
||||
// so an initial read of 1 byte would not work correctly.
|
||||
if size < 512 {
|
||||
size = 512
|
||||
}
|
||||
|
||||
data := make([]byte, 0, size)
|
||||
for {
|
||||
if len(data) >= cap(data) {
|
||||
d := append(data[:cap(data)], 0)
|
||||
data = d[:len(data)]
|
||||
}
|
||||
n, err := f.Read(data[len(data):cap(data)])
|
||||
data = data[:len(data)+n]
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return data, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WriteFile writes data to the named file, creating it if necessary.
|
||||
// If the file does not exist, WriteFile creates it with permissions perm (before umask);
|
||||
// otherwise WriteFile truncates it before writing, without changing permissions.
|
||||
func WriteFile(name string, data []byte, perm FileMode) error {
|
||||
f, err := OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(data)
|
||||
if err1 := f.Close(); err1 != nil && err == nil {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// The defined file mode bits are the most significant bits of the FileMode.
|
||||
// The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
|
||||
// The values of these bits should be considered part of the public API and
|
||||
// may be used in wire protocols or disk representations: they must not be
|
||||
// changed, although new bits might be added.
|
||||
const (
|
||||
// The single letters are the abbreviations
|
||||
// used by the String method's formatting.
|
||||
ModeDir = fs.ModeDir // d: is a directory
|
||||
ModeAppend = fs.ModeAppend // a: append-only
|
||||
ModeExclusive = fs.ModeExclusive // l: exclusive use
|
||||
ModeTemporary = fs.ModeTemporary // T: temporary file; Plan 9 only
|
||||
ModeSymlink = fs.ModeSymlink // L: symbolic link
|
||||
ModeDevice = fs.ModeDevice // D: device file
|
||||
ModeNamedPipe = fs.ModeNamedPipe // p: named pipe (FIFO)
|
||||
ModeSocket = fs.ModeSocket // S: Unix domain socket
|
||||
ModeSetuid = fs.ModeSetuid // u: setuid
|
||||
ModeSetgid = fs.ModeSetgid // g: setgid
|
||||
ModeCharDevice = fs.ModeCharDevice // c: Unix character device, when ModeDevice is set
|
||||
ModeSticky = fs.ModeSticky // t: sticky
|
||||
ModeIrregular = fs.ModeIrregular // ?: non-regular file; nothing else is known about this file
|
||||
|
||||
// Mask for the type bits. For regular files, none will be set.
|
||||
ModeType = fs.ModeType
|
||||
|
||||
ModePerm = fs.ModePerm // Unix permission bits, 0o777
|
||||
)
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type (
|
||||
FileMode = fs.FileMode
|
||||
FileInfo = fs.FileInfo
|
||||
)
|
||||
|
||||
// The followings are copied from Go 1.16 or 1.17 official implementation:
|
||||
// https://github.com/golang/go/blob/go1.16/src/os/file.go
|
||||
|
||||
// DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir.
|
||||
//
|
||||
// Note that DirFS("/prefix") only guarantees that the Open calls it makes to the
|
||||
// operating system will begin with "/prefix": DirFS("/prefix").Open("file") is the
|
||||
// same as os.Open("/prefix/file"). So if /prefix/file is a symbolic link pointing outside
|
||||
// the /prefix tree, then using DirFS does not stop the access any more than using
|
||||
// os.Open does. DirFS is therefore not a general substitute for a chroot-style security
|
||||
// mechanism when the directory tree contains arbitrary content.
|
||||
func DirFS(dir string) fs.FS {
|
||||
return dirFS(dir)
|
||||
}
|
||||
|
||||
func containsAny(s, chars string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
for j := 0; j < len(chars); j++ {
|
||||
if s[i] == chars[j] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type dirFS string
|
||||
|
||||
func (dir dirFS) Open(name string) (fs.File, error) {
|
||||
if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
|
||||
return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid}
|
||||
}
|
||||
f, err := Open(string(dir) + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err // nil fs.File
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (dir dirFS) Stat(name string) (fs.FileInfo, error) {
|
||||
if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
|
||||
return nil, &PathError{Op: "stat", Path: name, Err: ErrInvalid}
|
||||
}
|
||||
f, err := Stat(string(dir) + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// ReadFile reads the named file and returns the contents.
|
||||
// A successful call returns err == nil, not err == EOF.
|
||||
// Because ReadFile reads the whole file, it does not treat an EOF from Read
|
||||
// as an error to be reported.
|
||||
func ReadFile(name string) ([]byte, error) {
|
||||
f, err := Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var size int
|
||||
if info, err := f.Stat(); err == nil {
|
||||
size64 := info.Size()
|
||||
if int64(int(size64)) == size64 {
|
||||
size = int(size64)
|
||||
}
|
||||
}
|
||||
size++ // one byte for final read at EOF
|
||||
|
||||
// If a file claims a small size, read at least 512 bytes.
|
||||
// In particular, files in Linux's /proc claim size 0 but
|
||||
// then do not work right if read in small pieces,
|
||||
// so an initial read of 1 byte would not work correctly.
|
||||
if size < 512 {
|
||||
size = 512
|
||||
}
|
||||
|
||||
data := make([]byte, 0, size)
|
||||
for {
|
||||
if len(data) >= cap(data) {
|
||||
d := append(data[:cap(data)], 0)
|
||||
data = d[:len(data)]
|
||||
}
|
||||
n, err := f.Read(data[len(data):cap(data)])
|
||||
data = data[:len(data)+n]
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return data, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WriteFile writes data to the named file, creating it if necessary.
|
||||
// If the file does not exist, WriteFile creates it with permissions perm (before umask);
|
||||
// otherwise WriteFile truncates it before writing, without changing permissions.
|
||||
func WriteFile(name string, data []byte, perm FileMode) error {
|
||||
f, err := OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(data)
|
||||
if err1 := f.Close(); err1 != nil && err == nil {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// The defined file mode bits are the most significant bits of the FileMode.
|
||||
// The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
|
||||
// The values of these bits should be considered part of the public API and
|
||||
// may be used in wire protocols or disk representations: they must not be
|
||||
// changed, although new bits might be added.
|
||||
const (
|
||||
// The single letters are the abbreviations
|
||||
// used by the String method's formatting.
|
||||
ModeDir = fs.ModeDir // d: is a directory
|
||||
ModeAppend = fs.ModeAppend // a: append-only
|
||||
ModeExclusive = fs.ModeExclusive // l: exclusive use
|
||||
ModeTemporary = fs.ModeTemporary // T: temporary file; Plan 9 only
|
||||
ModeSymlink = fs.ModeSymlink // L: symbolic link
|
||||
ModeDevice = fs.ModeDevice // D: device file
|
||||
ModeNamedPipe = fs.ModeNamedPipe // p: named pipe (FIFO)
|
||||
ModeSocket = fs.ModeSocket // S: Unix domain socket
|
||||
ModeSetuid = fs.ModeSetuid // u: setuid
|
||||
ModeSetgid = fs.ModeSetgid // g: setgid
|
||||
ModeCharDevice = fs.ModeCharDevice // c: Unix character device, when ModeDevice is set
|
||||
ModeSticky = fs.ModeSticky // t: sticky
|
||||
ModeIrregular = fs.ModeIrregular // ?: non-regular file; nothing else is known about this file
|
||||
|
||||
// Mask for the type bits. For regular files, none will be set.
|
||||
ModeType = fs.ModeType
|
||||
|
||||
ModePerm = fs.ModePerm // Unix permission bits, 0o777
|
||||
)
|
|
@ -1,72 +0,0 @@
|
|||
// 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.
|
||||
|
||||
//go:build go1.16 && !baremetal && !js && !wasi
|
||||
// +build go1.16,!baremetal,!js,!wasi
|
||||
|
||||
// DirFS tests copied verbatim from upstream os_test.go, and adjusted minimally to fit tinygo.
|
||||
|
||||
package os_test
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
. "os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
)
|
||||
|
||||
func TestDirFS(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Log("TODO: implement Readdir for Windows")
|
||||
return
|
||||
}
|
||||
if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test that Open does not accept backslash as separator.
|
||||
d := DirFS(".")
|
||||
_, err := d.Open(`testdata\dirfs`)
|
||||
if err == nil {
|
||||
t.Fatalf(`Open testdata\dirfs succeeded`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirFSPathsValid(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Log("skipping on Windows")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: switch back to t.TempDir once it's implemented
|
||||
d, err := MkdirTemp("", "TestDirFSPathsValid")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer Remove(d)
|
||||
if err := os.WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer Remove(filepath.Join(d, "control.txt"))
|
||||
if err := os.WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer Remove(filepath.Join(d, `e:xperi\ment.txt`))
|
||||
|
||||
fsys := os.DirFS(d)
|
||||
err = fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error {
|
||||
if fs.ValidPath(e.Name()) {
|
||||
t.Logf("%q ok", e.Name())
|
||||
} else {
|
||||
t.Errorf("%q INVALID", e.Name())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
//go:build !go1.16
|
||||
// +build !go1.16
|
||||
|
||||
package os
|
||||
|
||||
import "time"
|
||||
|
||||
// A FileInfo describes a file and is returned by Stat and Lstat.
|
||||
type FileInfo interface {
|
||||
Name() string // base name of the file
|
||||
Size() int64 // length in bytes for regular files; system-dependent for others
|
||||
Mode() FileMode // file mode bits
|
||||
ModTime() time.Time // modification time
|
||||
IsDir() bool // abbreviation for Mode().IsDir()
|
||||
Sys() interface{} // underlying data source (can return nil)
|
||||
}
|
||||
|
||||
type FileMode uint32
|
||||
|
||||
// Mode constants, copied from the mainline Go source
|
||||
// https://github.com/golang/go/blob/4ce6a8e89668b87dce67e2f55802903d6eb9110a/src/os/types.go#L35-L63
|
||||
const (
|
||||
// The single letters are the abbreviations used by the String method's formatting.
|
||||
ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory
|
||||
ModeAppend // a: append-only
|
||||
ModeExclusive // l: exclusive use
|
||||
ModeTemporary // T: temporary file; Plan 9 only
|
||||
ModeSymlink // L: symbolic link
|
||||
ModeDevice // D: device file
|
||||
ModeNamedPipe // p: named pipe (FIFO)
|
||||
ModeSocket // S: Unix domain socket
|
||||
ModeSetuid // u: setuid
|
||||
ModeSetgid // g: setgid
|
||||
ModeCharDevice // c: Unix character device, when ModeDevice is set
|
||||
ModeSticky // t: sticky
|
||||
ModeIrregular // ?: non-regular file; nothing else is known about this file
|
||||
|
||||
// Mask for the type bits. For regular files, none will be set.
|
||||
ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular
|
||||
|
||||
ModePerm FileMode = 0777 // Unix permission bits
|
||||
)
|
||||
|
||||
// IsDir is a stub, always returning false
|
||||
func (m FileMode) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRegular is a stub, always returning false
|
||||
func (m FileMode) IsRegular() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Perm is a stub, always returning 0.
|
||||
func (m FileMode) Perm() FileMode {
|
||||
return 0
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
package os_test
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
. "os"
|
||||
"path/filepath"
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -55,8 +57,7 @@ func TestStatBadDir(t *testing.T) {
|
|||
dir := TempDir()
|
||||
badDir := filepath.Join(dir, "not-exist/really-not-exist")
|
||||
_, err := Stat(badDir)
|
||||
// TODO: PathError moved to io/fs in go 1.16; fix next line once we drop go 1.15 support.
|
||||
if pe, ok := err.(*PathError); !ok || !IsNotExist(err) || pe.Path != badDir {
|
||||
if pe, ok := err.(*fs.PathError); !ok || !IsNotExist(err) || pe.Path != badDir {
|
||||
t.Errorf("Mkdir error = %#v; want PathError for path %q satisifying IsNotExist", err, badDir)
|
||||
}
|
||||
}
|
||||
|
@ -123,8 +124,7 @@ func TestRemove(t *testing.T) {
|
|||
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 {
|
||||
if pe, ok := err.(*fs.PathError); !ok {
|
||||
t.Errorf("TestRemove: expected PathError, got err %q", err.Error())
|
||||
} else {
|
||||
if pe.Path != f {
|
||||
|
@ -271,3 +271,55 @@ func TestUserHomeDir(t *testing.T) {
|
|||
t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirFS(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Log("TODO: implement Readdir for Windows")
|
||||
return
|
||||
}
|
||||
if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test that Open does not accept backslash as separator.
|
||||
d := DirFS(".")
|
||||
_, err := d.Open(`testdata\dirfs`)
|
||||
if err == nil {
|
||||
t.Fatalf(`Open testdata\dirfs succeeded`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirFSPathsValid(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Log("skipping on Windows")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: switch back to t.TempDir once it's implemented
|
||||
d, err := MkdirTemp("", "TestDirFSPathsValid")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer Remove(d)
|
||||
if err := WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer Remove(filepath.Join(d, "control.txt"))
|
||||
if err := WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer Remove(filepath.Join(d, `e:xperi\ment.txt`))
|
||||
|
||||
fsys := DirFS(d)
|
||||
err = fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error {
|
||||
if fs.ValidPath(e.Name()) {
|
||||
t.Logf("%q ok", e.Name())
|
||||
} else {
|
||||
t.Errorf("%q INVALID", e.Name())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ package os_test
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
. "os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
@ -157,8 +158,7 @@ func TestMkdirTempBadDir(t *testing.T) {
|
|||
|
||||
badDir := filepath.Join(dir, "not-exist")
|
||||
_, err = MkdirTemp(badDir, "foo")
|
||||
// TODO: when we drop support for go 1.15, PathError should move to fs
|
||||
if pe, ok := err.(*PathError); !ok || !IsNotExist(err) || pe.Path != badDir {
|
||||
if pe, ok := err.(*fs.PathError); !ok || !IsNotExist(err) || pe.Path != badDir {
|
||||
t.Errorf("TempDir error = %#v; want PathError for path %q satisifying IsNotExist", err, badDir)
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче