1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package afero
17
18 import (
19 "bytes"
20 "io"
21 "os"
22 "path/filepath"
23 "sort"
24 "strconv"
25 "strings"
26 "sync"
27 "time"
28 )
29
30
31 type byName []os.FileInfo
32
33 func (f byName) Len() int { return len(f) }
34 func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
35 func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
36
37
38
39 func (a Afero) ReadDir(dirname string) ([]os.FileInfo, error) {
40 return ReadDir(a.Fs, dirname)
41 }
42
43 func ReadDir(fs Fs, dirname string) ([]os.FileInfo, error) {
44 f, err := fs.Open(dirname)
45 if err != nil {
46 return nil, err
47 }
48 list, err := f.Readdir(-1)
49 f.Close()
50 if err != nil {
51 return nil, err
52 }
53 sort.Sort(byName(list))
54 return list, nil
55 }
56
57
58
59
60
61 func (a Afero) ReadFile(filename string) ([]byte, error) {
62 return ReadFile(a.Fs, filename)
63 }
64
65 func ReadFile(fs Fs, filename string) ([]byte, error) {
66 f, err := fs.Open(filename)
67 if err != nil {
68 return nil, err
69 }
70 defer f.Close()
71
72
73 var n int64
74
75 if fi, err := f.Stat(); err == nil {
76
77 if size := fi.Size(); size < 1e9 {
78 n = size
79 }
80 }
81
82
83
84
85
86 return readAll(f, n+bytes.MinRead)
87 }
88
89
90
91 func readAll(r io.Reader, capacity int64) (b []byte, err error) {
92 buf := bytes.NewBuffer(make([]byte, 0, capacity))
93
94
95 defer func() {
96 e := recover()
97 if e == nil {
98 return
99 }
100 if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
101 err = panicErr
102 } else {
103 panic(e)
104 }
105 }()
106 _, err = buf.ReadFrom(r)
107 return buf.Bytes(), err
108 }
109
110
111
112
113
114 func ReadAll(r io.Reader) ([]byte, error) {
115 return readAll(r, bytes.MinRead)
116 }
117
118
119
120
121 func (a Afero) WriteFile(filename string, data []byte, perm os.FileMode) error {
122 return WriteFile(a.Fs, filename, data, perm)
123 }
124
125 func WriteFile(fs Fs, filename string, data []byte, perm os.FileMode) error {
126 f, err := fs.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
127 if err != nil {
128 return err
129 }
130 n, err := f.Write(data)
131 if err == nil && n < len(data) {
132 err = io.ErrShortWrite
133 }
134 if err1 := f.Close(); err == nil {
135 err = err1
136 }
137 return err
138 }
139
140
141
142
143
144 var (
145 randNum uint32
146 randmu sync.Mutex
147 )
148
149 func reseed() uint32 {
150 return uint32(time.Now().UnixNano() + int64(os.Getpid()))
151 }
152
153 func nextRandom() string {
154 randmu.Lock()
155 r := randNum
156 if r == 0 {
157 r = reseed()
158 }
159 r = r*1664525 + 1013904223
160 randNum = r
161 randmu.Unlock()
162 return strconv.Itoa(int(1e9 + r%1e9))[1:]
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176 func (a Afero) TempFile(dir, pattern string) (f File, err error) {
177 return TempFile(a.Fs, dir, pattern)
178 }
179
180 func TempFile(fs Fs, dir, pattern string) (f File, err error) {
181 if dir == "" {
182 dir = os.TempDir()
183 }
184
185 var prefix, suffix string
186 if pos := strings.LastIndex(pattern, "*"); pos != -1 {
187 prefix, suffix = pattern[:pos], pattern[pos+1:]
188 } else {
189 prefix = pattern
190 }
191
192 nconflict := 0
193 for i := 0; i < 10000; i++ {
194 name := filepath.Join(dir, prefix+nextRandom()+suffix)
195 f, err = fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o600)
196 if os.IsExist(err) {
197 if nconflict++; nconflict > 10 {
198 randmu.Lock()
199 randNum = reseed()
200 randmu.Unlock()
201 }
202 continue
203 }
204 break
205 }
206 return
207 }
208
209
210
211
212
213
214
215
216 func (a Afero) TempDir(dir, prefix string) (name string, err error) {
217 return TempDir(a.Fs, dir, prefix)
218 }
219
220 func TempDir(fs Fs, dir, prefix string) (name string, err error) {
221 if dir == "" {
222 dir = os.TempDir()
223 }
224
225 nconflict := 0
226 for i := 0; i < 10000; i++ {
227 try := filepath.Join(dir, prefix+nextRandom())
228 err = fs.Mkdir(try, 0o700)
229 if os.IsExist(err) {
230 if nconflict++; nconflict > 10 {
231 randmu.Lock()
232 randNum = reseed()
233 randmu.Unlock()
234 }
235 continue
236 }
237 if err == nil {
238 name = try
239 }
240 break
241 }
242 return
243 }
244
View as plain text