podman
1// Copyright ©2015 The Go Authors
2// Copyright ©2015 Steve Francia <spf@spf13.com>
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16package afero17
18import (19"bytes"20"io"21"os"22"path/filepath"23"sort"24"strconv"25"strings"26"sync"27"time"28)
29
30// byName implements sort.Interface.
31type byName []os.FileInfo32
33func (f byName) Len() int { return len(f) }34func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }35func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }36
37// ReadDir reads the directory named by dirname and returns
38// a list of sorted directory entries.
39func (a Afero) ReadDir(dirname string) ([]os.FileInfo, error) {40return ReadDir(a.Fs, dirname)41}
42
43func ReadDir(fs Fs, dirname string) ([]os.FileInfo, error) {44f, err := fs.Open(dirname)45if err != nil {46return nil, err47}48list, err := f.Readdir(-1)49f.Close()50if err != nil {51return nil, err52}53sort.Sort(byName(list))54return list, nil55}
56
57// ReadFile reads the file named by filename and returns the contents.
58// A successful call returns err == nil, not err == EOF. Because ReadFile
59// reads the whole file, it does not treat an EOF from Read as an error
60// to be reported.
61func (a Afero) ReadFile(filename string) ([]byte, error) {62return ReadFile(a.Fs, filename)63}
64
65func ReadFile(fs Fs, filename string) ([]byte, error) {66f, err := fs.Open(filename)67if err != nil {68return nil, err69}70defer f.Close()71// It's a good but not certain bet that FileInfo will tell us exactly how much to72// read, so let's try it but be prepared for the answer to be wrong.73var n int6474
75if fi, err := f.Stat(); err == nil {76// Don't preallocate a huge buffer, just in case.77if size := fi.Size(); size < 1e9 {78n = size79}80}81// As initial capacity for readAll, use n + a little extra in case Size is zero,82// and to avoid another allocation after Read has filled the buffer. The readAll83// call will read into its allocated internal buffer cheaply. If the size was84// wrong, we'll either waste some space off the end or reallocate as needed, but85// in the overwhelmingly common case we'll get it just right.86return readAll(f, n+bytes.MinRead)87}
88
89// readAll reads from r until an error or EOF and returns the data it read
90// from the internal buffer allocated with a specified capacity.
91func readAll(r io.Reader, capacity int64) (b []byte, err error) {92buf := bytes.NewBuffer(make([]byte, 0, capacity))93// If the buffer overflows, we will get bytes.ErrTooLarge.94// Return that as an error. Any other panic remains.95defer func() {96e := recover()97if e == nil {98return99}100if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {101err = panicErr102} else {103panic(e)104}105}()106_, err = buf.ReadFrom(r)107return buf.Bytes(), err108}
109
110// ReadAll reads from r until an error or EOF and returns the data it read.
111// A successful call returns err == nil, not err == EOF. Because ReadAll is
112// defined to read from src until EOF, it does not treat an EOF from Read
113// as an error to be reported.
114func ReadAll(r io.Reader) ([]byte, error) {115return readAll(r, bytes.MinRead)116}
117
118// WriteFile writes data to a file named by filename.
119// If the file does not exist, WriteFile creates it with permissions perm;
120// otherwise WriteFile truncates it before writing.
121func (a Afero) WriteFile(filename string, data []byte, perm os.FileMode) error {122return WriteFile(a.Fs, filename, data, perm)123}
124
125func WriteFile(fs Fs, filename string, data []byte, perm os.FileMode) error {126f, err := fs.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)127if err != nil {128return err129}130n, err := f.Write(data)131if err == nil && n < len(data) {132err = io.ErrShortWrite133}134if err1 := f.Close(); err == nil {135err = err1136}137return err138}
139
140// Random number state.
141// We generate random temporary file names so that there's a good
142// chance the file doesn't exist yet - keeps the number of tries in
143// TempFile to a minimum.
144var (145randNum uint32146randmu sync.Mutex147)
148
149func reseed() uint32 {150return uint32(time.Now().UnixNano() + int64(os.Getpid()))151}
152
153func nextRandom() string {154randmu.Lock()155r := randNum156if r == 0 {157r = reseed()158}159r = r*1664525 + 1013904223 // constants from Numerical Recipes160randNum = r161randmu.Unlock()162return strconv.Itoa(int(1e9 + r%1e9))[1:]163}
164
165// TempFile creates a new temporary file in the directory dir,
166// opens the file for reading and writing, and returns the resulting *os.File.
167// The filename is generated by taking pattern and adding a random
168// string to the end. If pattern includes a "*", the random string
169// replaces the last "*".
170// If dir is the empty string, TempFile uses the default directory
171// for temporary files (see os.TempDir).
172// Multiple programs calling TempFile simultaneously
173// will not choose the same file. The caller can use f.Name()
174// to find the pathname of the file. It is the caller's responsibility
175// to remove the file when no longer needed.
176func (a Afero) TempFile(dir, pattern string) (f File, err error) {177return TempFile(a.Fs, dir, pattern)178}
179
180func TempFile(fs Fs, dir, pattern string) (f File, err error) {181if dir == "" {182dir = os.TempDir()183}184
185var prefix, suffix string186if pos := strings.LastIndex(pattern, "*"); pos != -1 {187prefix, suffix = pattern[:pos], pattern[pos+1:]188} else {189prefix = pattern190}191
192nconflict := 0193for i := 0; i < 10000; i++ {194name := filepath.Join(dir, prefix+nextRandom()+suffix)195f, err = fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o600)196if os.IsExist(err) {197if nconflict++; nconflict > 10 {198randmu.Lock()199randNum = reseed()200randmu.Unlock()201}202continue203}204break205}206return207}
208
209// TempDir creates a new temporary directory in the directory dir
210// with a name beginning with prefix and returns the path of the
211// new directory. If dir is the empty string, TempDir uses the
212// default directory for temporary files (see os.TempDir).
213// Multiple programs calling TempDir simultaneously
214// will not choose the same directory. It is the caller's responsibility
215// to remove the directory when no longer needed.
216func (a Afero) TempDir(dir, prefix string) (name string, err error) {217return TempDir(a.Fs, dir, prefix)218}
219
220func TempDir(fs Fs, dir, prefix string) (name string, err error) {221if dir == "" {222dir = os.TempDir()223}224
225nconflict := 0226for i := 0; i < 10000; i++ {227try := filepath.Join(dir, prefix+nextRandom())228err = fs.Mkdir(try, 0o700)229if os.IsExist(err) {230if nconflict++; nconflict > 10 {231randmu.Lock()232randNum = reseed()233randmu.Unlock()234}235continue236}237if err == nil {238name = try239}240break241}242return243}
244