aboutsummaryrefslogtreecommitdiff
path: root/src/os/file.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/os/file.go')
-rw-r--r--src/os/file.go36
1 files changed, 29 insertions, 7 deletions
diff --git a/src/os/file.go b/src/os/file.go
index 2823128554..8afc6e3540 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -37,12 +37,12 @@
// Note: The maximum number of concurrent operations on a File may be limited by
// the OS or the system. The number should be high, but exceeding it may degrade
// performance or cause other issues.
-//
package os
import (
"errors"
"internal/poll"
+ "internal/safefilepath"
"internal/testlog"
"internal/unsafeheader"
"io"
@@ -623,6 +623,8 @@ func isWindowsNulName(name string) bool {
// 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.
+//
+// The directory dir must not be "".
func DirFS(dir string) fs.FS {
return dirFS(dir)
}
@@ -641,10 +643,11 @@ func containsAny(s, chars string) bool {
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}
+ fullname, err := dir.join(name)
+ if err != nil {
+ return nil, &PathError{Op: "stat", Path: name, Err: err}
}
- f, err := Open(string(dir) + "/" + name)
+ f, err := Open(fullname)
if err != nil {
return nil, err // nil fs.File
}
@@ -652,16 +655,35 @@ func (dir dirFS) Open(name string) (fs.File, error) {
}
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}
+ fullname, err := dir.join(name)
+ if err != nil {
+ return nil, &PathError{Op: "stat", Path: name, Err: err}
}
- f, err := Stat(string(dir) + "/" + name)
+ f, err := Stat(fullname)
if err != nil {
return nil, err
}
return f, nil
}
+// join returns the path for name in dir.
+func (dir dirFS) join(name string) (string, error) {
+ if dir == "" {
+ return "", errors.New("os: DirFS with empty root")
+ }
+ if !fs.ValidPath(name) {
+ return "", ErrInvalid
+ }
+ name, err := safefilepath.FromFS(name)
+ if err != nil {
+ return "", ErrInvalid
+ }
+ if IsPathSeparator(dir[len(dir)-1]) {
+ return string(dir) + name, nil
+ }
+ return string(dir) + string(PathSeparator) + name, 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