1// Copyright 2021, 2022 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15//go:build go1.16 16// +build go1.16 17 18package runfiles 19 20import ( 21 "errors" 22 "io" 23 "io/fs" 24 "os" 25 "time" 26) 27 28// Open implements fs.FS.Open. 29func (r *Runfiles) Open(name string) (fs.File, error) { 30 if !fs.ValidPath(name) { 31 return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid} 32 } 33 p, err := r.Rlocation(name) 34 if errors.Is(err, ErrEmpty) { 35 return emptyFile(name), nil 36 } 37 if err != nil { 38 return nil, pathError("open", name, err) 39 } 40 return os.Open(p) 41} 42 43// Stat implements fs.StatFS.Stat. 44func (r *Runfiles) Stat(name string) (fs.FileInfo, error) { 45 if !fs.ValidPath(name) { 46 return nil, &fs.PathError{Op: "stat", Path: name, Err: fs.ErrInvalid} 47 } 48 p, err := r.Rlocation(name) 49 if errors.Is(err, ErrEmpty) { 50 return emptyFileInfo(name), nil 51 } 52 if err != nil { 53 return nil, pathError("stat", name, err) 54 } 55 return os.Stat(p) 56} 57 58// ReadFile implements fs.ReadFileFS.ReadFile. 59func (r *Runfiles) ReadFile(name string) ([]byte, error) { 60 if !fs.ValidPath(name) { 61 return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid} 62 } 63 p, err := r.Rlocation(name) 64 if errors.Is(err, ErrEmpty) { 65 return nil, nil 66 } 67 if err != nil { 68 return nil, pathError("open", name, err) 69 } 70 return os.ReadFile(p) 71} 72 73type emptyFile string 74 75func (f emptyFile) Stat() (fs.FileInfo, error) { return emptyFileInfo(f), nil } 76func (f emptyFile) Read([]byte) (int, error) { return 0, io.EOF } 77func (emptyFile) Close() error { return nil } 78 79type emptyFileInfo string 80 81func (i emptyFileInfo) Name() string { return string(i) } 82func (emptyFileInfo) Size() int64 { return 0 } 83func (emptyFileInfo) Mode() fs.FileMode { return 0444 } 84func (emptyFileInfo) ModTime() time.Time { return time.Time{} } 85func (emptyFileInfo) IsDir() bool { return false } 86func (emptyFileInfo) Sys() interface{} { return nil } 87 88func pathError(op, name string, err error) error { 89 if err == nil { 90 return nil 91 } 92 var rerr Error 93 if errors.As(err, &rerr) { 94 // Unwrap the error because we don’t need the failing name 95 // twice. 96 return &fs.PathError{Op: op, Path: rerr.Name, Err: rerr.Err} 97 } 98 return &fs.PathError{Op: op, Path: name, Err: err} 99} 100