// Copyright 2021 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. //go:build go1.16 // +build go1.16 package vfs import ( "io/fs" "os" "path" "strings" ) // FromFS converts an fs.FS to the FileSystem interface. func FromFS(fsys fs.FS) FileSystem { return &fsysToFileSystem{fsys} } type fsysToFileSystem struct { fsys fs.FS } func (f *fsysToFileSystem) fsPath(name string) string { name = path.Clean(name) if name == "/" { return "." } return strings.TrimPrefix(name, "/") } func (f *fsysToFileSystem) Open(name string) (ReadSeekCloser, error) { file, err := f.fsys.Open(f.fsPath(name)) if err != nil { return nil, err } if rsc, ok := file.(ReadSeekCloser); ok { return rsc, nil } return &noSeekFile{f.fsPath(name), file}, nil } func (f *fsysToFileSystem) Lstat(name string) (os.FileInfo, error) { return fs.Stat(f.fsys, f.fsPath(name)) } func (f *fsysToFileSystem) Stat(name string) (os.FileInfo, error) { return fs.Stat(f.fsys, f.fsPath(name)) } func (f *fsysToFileSystem) RootType(name string) RootType { return "" } func (f *fsysToFileSystem) ReadDir(name string) ([]os.FileInfo, error) { dirs, err := fs.ReadDir(f.fsys, f.fsPath(name)) var infos []os.FileInfo for _, d := range dirs { info, err1 := d.Info() if err1 != nil { if err == nil { err = err1 } continue } infos = append(infos, info) } return infos, err } func (f *fsysToFileSystem) String() string { return "io/fs" } type noSeekFile struct { path string fs.File } func (f *noSeekFile) Seek(offset int64, whence int) (int64, error) { return 0, &fs.PathError{Op: "seek", Path: f.path, Err: fs.ErrInvalid} }