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