mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-09 21:43:40 +00:00
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.
This commit is contained in:
+144
-17
@@ -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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user