// Copyright 2020 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 fsimport ()// A SubFS is a file system with a Sub method.typeSubFSinterface {FS// Sub returns an FS corresponding to the subtree rooted at dir.Sub(dir string) (FS, error)}// Sub returns an [FS] corresponding to the subtree rooted at fsys's dir.//// If dir is ".", Sub returns fsys unchanged.// Otherwise, if fs implements [SubFS], Sub returns fsys.Sub(dir).// Otherwise, Sub returns a new [FS] implementation sub that,// in effect, implements sub.Open(name) as fsys.Open(path.Join(dir, name)).// The implementation also translates calls to ReadDir, ReadFile, and Glob appropriately.//// Note that Sub(os.DirFS("/"), "prefix") is equivalent to os.DirFS("/prefix")// and that neither of them guarantees to avoid operating system// accesses outside "/prefix", because the implementation of [os.DirFS]// does not check for symbolic links inside "/prefix" that point to// other directories. That is, [os.DirFS] is not a general substitute for a// chroot-style security mechanism, and Sub does not change that fact.func ( FS, string) (FS, error) {if !ValidPath() {returnnil, &PathError{Op: "sub", Path: , Err: ErrInvalid} }if == "." {return , nil }if , := .(SubFS); {return .Sub() }return &subFS{, }, nil}type subFS struct { fsys FS dir string}// fullName maps name to the fully-qualified name dir/name.func ( *subFS) ( string, string) (string, error) {if !ValidPath() {return"", &PathError{Op: , Path: , Err: ErrInvalid} }returnpath.Join(.dir, ), nil}// shorten maps name, which should start with f.dir, back to the suffix after f.dir.func ( *subFS) ( string) ( string, bool) {if == .dir {return".", true }iflen() >= len(.dir)+2 && [len(.dir)] == '/' && [:len(.dir)] == .dir {return [len(.dir)+1:], true }return"", false}// fixErr shortens any reported names in PathErrors by stripping f.dir.func ( *subFS) ( error) error {if , := .(*PathError); {if , := .shorten(.Path); { .Path = } }return}func ( *subFS) ( string) (File, error) { , := .fullName("open", )if != nil {returnnil, } , := .fsys.Open()return , .fixErr()}func ( *subFS) ( string) ([]DirEntry, error) { , := .fullName("read", )if != nil {returnnil, } , := ReadDir(.fsys, )return , .fixErr()}func ( *subFS) ( string) ([]byte, error) { , := .fullName("read", )if != nil {returnnil, } , := ReadFile(.fsys, )return , .fixErr()}func ( *subFS) ( string) ([]string, error) {// Check pattern is well-formed.if , := path.Match(, ""); != nil {returnnil, }if == "." {return []string{"."}, nil } := .dir + "/" + , := Glob(.fsys, )for , := range { , := .shorten()if ! {returnnil, errors.New("invalid result from inner fsys Glob: " + + " not in " + .dir) // can't use fmt in this package } [] = }return , .fixErr()}func ( *subFS) ( string) (FS, error) {if == "." {return , nil } , := .fullName("sub", )if != nil {returnnil, }return &subFS{.fsys, }, nil}
The pages are generated with Goldsv0.6.9-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.