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