Source file src/pkg/os/file_unix.go
1
2
3
4
5
6
7 package os
8
9 import (
10 "internal/poll"
11 "internal/syscall/unix"
12 "io"
13 "runtime"
14 "syscall"
15 )
16
17
18 func fixLongPath(path string) string {
19 return path
20 }
21
22 func rename(oldname, newname string) error {
23 fi, err := Lstat(newname)
24 if err == nil && fi.IsDir() {
25
26
27
28
29
30 if _, err := Lstat(oldname); err != nil {
31 if pe, ok := err.(*PathError); ok {
32 err = pe.Err
33 }
34 return &LinkError{"rename", oldname, newname, err}
35 }
36 return &LinkError{"rename", oldname, newname, syscall.EEXIST}
37 }
38 err = syscall.Rename(oldname, newname)
39 if err != nil {
40 return &LinkError{"rename", oldname, newname, err}
41 }
42 return nil
43 }
44
45
46
47
48
49 type file struct {
50 pfd poll.FD
51 name string
52 dirinfo *dirInfo
53 nonblock bool
54 stdoutOrErr bool
55 appendMode bool
56 }
57
58
59
60
61 func (f *File) Fd() uintptr {
62 if f == nil {
63 return ^(uintptr(0))
64 }
65
66
67
68
69
70
71 if f.nonblock {
72 f.pfd.SetBlocking()
73 }
74
75 return uintptr(f.pfd.Sysfd)
76 }
77
78
79
80
81
82
83 func NewFile(fd uintptr, name string) *File {
84 kind := kindNewFile
85 if nb, err := unix.IsNonblock(int(fd)); err == nil && nb {
86 kind = kindNonBlock
87 }
88 return newFile(fd, name, kind)
89 }
90
91
92 type newFileKind int
93
94 const (
95 kindNewFile newFileKind = iota
96 kindOpenFile
97 kindPipe
98 kindNonBlock
99 )
100
101
102
103
104 func newFile(fd uintptr, name string, kind newFileKind) *File {
105 fdi := int(fd)
106 if fdi < 0 {
107 return nil
108 }
109 f := &File{&file{
110 pfd: poll.FD{
111 Sysfd: fdi,
112 IsStream: true,
113 ZeroReadIsEOF: true,
114 },
115 name: name,
116 stdoutOrErr: fdi == 1 || fdi == 2,
117 }}
118
119 pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock
120
121
122
123
124 if kind == kindOpenFile {
125 switch runtime.GOOS {
126 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd":
127 var st syscall.Stat_t
128 err := syscall.Fstat(fdi, &st)
129 typ := st.Mode & syscall.S_IFMT
130
131
132
133
134
135
136
137 if err == nil && (typ == syscall.S_IFREG || typ == syscall.S_IFDIR) {
138 pollable = false
139 }
140
141
142
143
144
145 if runtime.GOOS == "darwin" && typ == syscall.S_IFIFO {
146 pollable = false
147 }
148 }
149 }
150
151 if err := f.pfd.Init("file", pollable); err != nil {
152
153
154
155
156
157
158 } else if pollable {
159
160
161 if err := syscall.SetNonblock(fdi, true); err == nil {
162 f.nonblock = true
163 }
164 }
165
166 runtime.SetFinalizer(f.file, (*file).close)
167 return f
168 }
169
170
171
172
173 func epipecheck(file *File, e error) {
174 if e == syscall.EPIPE && file.stdoutOrErr {
175 sigpipe()
176 }
177 }
178
179
180
181 const DevNull = "/dev/null"
182
183
184
185 func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
186 setSticky := false
187 if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
188 if _, err := Stat(name); IsNotExist(err) {
189 setSticky = true
190 }
191 }
192
193 var r int
194 for {
195 var e error
196 r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
197 if e == nil {
198 break
199 }
200
201
202
203
204 if runtime.GOOS == "darwin" && e == syscall.EINTR {
205 continue
206 }
207
208 return nil, &PathError{"open", name, e}
209 }
210
211
212 if setSticky {
213 setStickyBit(name)
214 }
215
216
217
218 if !supportsCloseOnExec {
219 syscall.CloseOnExec(r)
220 }
221
222 return newFile(uintptr(r), name, kindOpenFile), nil
223 }
224
225
226
227
228
229 func (f *File) Close() error {
230 if f == nil {
231 return ErrInvalid
232 }
233 return f.file.close()
234 }
235
236 func (file *file) close() error {
237 if file == nil {
238 return syscall.EINVAL
239 }
240 if file.dirinfo != nil {
241 file.dirinfo.close()
242 }
243 var err error
244 if e := file.pfd.Close(); e != nil {
245 if e == poll.ErrFileClosing {
246 e = ErrClosed
247 }
248 err = &PathError{"close", file.name, e}
249 }
250
251
252 runtime.SetFinalizer(file, nil)
253 return err
254 }
255
256
257
258 func (f *File) read(b []byte) (n int, err error) {
259 n, err = f.pfd.Read(b)
260 runtime.KeepAlive(f)
261 return n, err
262 }
263
264
265
266
267 func (f *File) pread(b []byte, off int64) (n int, err error) {
268 n, err = f.pfd.Pread(b, off)
269 runtime.KeepAlive(f)
270 return n, err
271 }
272
273
274
275 func (f *File) write(b []byte) (n int, err error) {
276 n, err = f.pfd.Write(b)
277 runtime.KeepAlive(f)
278 return n, err
279 }
280
281
282
283 func (f *File) pwrite(b []byte, off int64) (n int, err error) {
284 n, err = f.pfd.Pwrite(b, off)
285 runtime.KeepAlive(f)
286 return n, err
287 }
288
289
290
291
292
293 func (f *File) seek(offset int64, whence int) (ret int64, err error) {
294 ret, err = f.pfd.Seek(offset, whence)
295 runtime.KeepAlive(f)
296 return ret, err
297 }
298
299
300
301
302 func Truncate(name string, size int64) error {
303 if e := syscall.Truncate(name, size); e != nil {
304 return &PathError{"truncate", name, e}
305 }
306 return nil
307 }
308
309
310
311 func Remove(name string) error {
312
313
314
315
316 e := syscall.Unlink(name)
317 if e == nil {
318 return nil
319 }
320 e1 := syscall.Rmdir(name)
321 if e1 == nil {
322 return nil
323 }
324
325
326
327
328
329
330
331
332
333
334 if e1 != syscall.ENOTDIR {
335 e = e1
336 }
337 return &PathError{"remove", name, e}
338 }
339
340 func tempDir() string {
341 dir := Getenv("TMPDIR")
342 if dir == "" {
343 if runtime.GOOS == "android" {
344 dir = "/data/local/tmp"
345 } else {
346 dir = "/tmp"
347 }
348 }
349 return dir
350 }
351
352
353
354 func Link(oldname, newname string) error {
355 e := syscall.Link(oldname, newname)
356 if e != nil {
357 return &LinkError{"link", oldname, newname, e}
358 }
359 return nil
360 }
361
362
363
364 func Symlink(oldname, newname string) error {
365 e := syscall.Symlink(oldname, newname)
366 if e != nil {
367 return &LinkError{"symlink", oldname, newname, e}
368 }
369 return nil
370 }
371
372 func (f *File) readdir(n int) (fi []FileInfo, err error) {
373 dirname := f.name
374 if dirname == "" {
375 dirname = "."
376 }
377 names, err := f.Readdirnames(n)
378 fi = make([]FileInfo, 0, len(names))
379 for _, filename := range names {
380 fip, lerr := lstat(dirname + "/" + filename)
381 if IsNotExist(lerr) {
382
383
384 continue
385 }
386 if lerr != nil {
387 return fi, lerr
388 }
389 fi = append(fi, fip)
390 }
391 if len(fi) == 0 && err == nil && n > 0 {
392
393
394 err = io.EOF
395 }
396 return fi, err
397 }
398
399
400
401 func Readlink(name string) (string, error) {
402 for len := 128; ; len *= 2 {
403 b := make([]byte, len)
404 n, e := fixCount(syscall.Readlink(name, b))
405
406 if runtime.GOOS == "aix" && e == syscall.ERANGE {
407 continue
408 }
409 if e != nil {
410 return "", &PathError{"readlink", name, e}
411 }
412 if n < len {
413 return string(b[0:n]), nil
414 }
415 }
416 }
417
View as plain text