diff options
Diffstat (limited to 'libgo/go/os/file.go')
-rw-r--r-- | libgo/go/os/file.go | 113 |
1 files changed, 100 insertions, 13 deletions
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go index a2b71cb..416bc0e 100644 --- a/libgo/go/os/file.go +++ b/libgo/go/os/file.go @@ -45,6 +45,7 @@ import ( "internal/poll" "internal/testlog" "io" + "io/fs" "runtime" "syscall" "time" @@ -127,7 +128,7 @@ func (f *File) ReadAt(b []byte, off int64) (n int, err error) { } if off < 0 { - return 0, &PathError{"readat", f.name, errors.New("negative offset")} + return 0, &PathError{Op: "readat", Path: f.name, Err: errors.New("negative offset")} } for len(b) > 0 { @@ -203,7 +204,7 @@ func (f *File) WriteAt(b []byte, off int64) (n int, err error) { } if off < 0 { - return 0, &PathError{"writeat", f.name, errors.New("negative offset")} + return 0, &PathError{Op: "writeat", Path: f.name, Err: errors.New("negative offset")} } for len(b) > 0 { @@ -253,12 +254,15 @@ func (f *File) WriteString(s string) (n int, err error) { // If there is an error, it will be of type *PathError. func Mkdir(name string, perm FileMode) error { if runtime.GOOS == "windows" && isWindowsNulName(name) { - return &PathError{"mkdir", name, syscall.ENOTDIR} + return &PathError{Op: "mkdir", Path: name, Err: syscall.ENOTDIR} } - e := syscall.Mkdir(fixLongPath(name), syscallMode(perm)) + longName := fixLongPath(name) + e := ignoringEINTR(func() error { + return syscall.Mkdir(longName, syscallMode(perm)) + }) if e != nil { - return &PathError{"mkdir", name, e} + return &PathError{Op: "mkdir", Path: name, Err: e} } // mkdir(2) itself won't handle the sticky bit on *BSD and Solaris @@ -288,7 +292,7 @@ func setStickyBit(name string) error { func Chdir(dir string) error { if e := syscall.Chdir(dir); e != nil { testlog.Open(dir) // observe likely non-existent directory - return &PathError{"chdir", dir, e} + return &PathError{Op: "chdir", Path: dir, Err: e} } if log := testlog.Logger(); log != nil { wd, err := Getwd() @@ -363,7 +367,7 @@ func (f *File) wrapErr(op string, err error) error { if err == poll.ErrFileClosing { err = ErrClosed } - return &PathError{op, f.name, err} + return &PathError{Op: op, Path: f.name, Err: err} } // TempDir returns the default directory to use for temporary files. @@ -402,7 +406,7 @@ func UserCacheDir() (string, error) { return "", errors.New("%LocalAppData% is not defined") } - case "darwin": + case "darwin", "ios": dir = Getenv("HOME") if dir == "" { return "", errors.New("$HOME is not defined") @@ -453,7 +457,7 @@ func UserConfigDir() (string, error) { return "", errors.New("%AppData% is not defined") } - case "darwin": + case "darwin", "ios": dir = Getenv("HOME") if dir == "" { return "", errors.New("$HOME is not defined") @@ -501,10 +505,8 @@ func UserHomeDir() (string, error) { switch runtime.GOOS { case "android": return "/sdcard", nil - case "darwin": - if runtime.GOARCH == "arm64" { - return "/", nil - } + case "ios": + return "/", nil } return "", errors.New(enverr + " is not defined") } @@ -605,3 +607,88 @@ func isWindowsNulName(name string) bool { } return true } + +// 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) +} + +type dirFS string + +func (dir dirFS) Open(name string) (fs.File, error) { + if !fs.ValidPath(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 +} + +// 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 +} |