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