| // 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 osfs |
| |
| import ( |
| "os" |
| "runtime" |
| |
| "golang.org/x/website/internal/backport/io/fs" |
| ) |
| |
| // 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, &os.PathError{Op: "open", Path: name, Err: os.ErrInvalid} |
| } |
| f, err := os.Open(string(dir) + "/" + name) |
| if err != nil { |
| return nil, err // nil fs.File |
| } |
| return dirFSFile{f}, nil |
| } |
| |
| func (dir dirFS) Stat(name string) (fs.FileInfo, error) { |
| if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { |
| return nil, &os.PathError{Op: "stat", Path: name, Err: os.ErrInvalid} |
| } |
| f, err := os.Stat(string(dir) + "/" + name) |
| if err != nil { |
| return nil, err |
| } |
| return f, nil |
| } |
| |
| type dirFSFile struct { |
| *os.File |
| } |
| |
| func (f dirFSFile) ReadDir(n int) ([]fs.DirEntry, error) { |
| infos, err := f.Readdir(n) |
| var dirs []fs.DirEntry |
| for _, info := range infos { |
| dirs = append(dirs, fs.FileInfoToDirEntry(info)) |
| } |
| return dirs, err |
| } |