jit: Fix Darwin bootstrap after r15-1699.
[official-gcc.git] / libgo / go / os / file_plan9.go
blob887e1c889232b3536c0e6db2483b42b66ac8b4bb
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package os
7 import (
8 "internal/poll"
9 "io"
10 "runtime"
11 "syscall"
12 "time"
15 // fixLongPath is a noop on non-Windows platforms.
16 func fixLongPath(path string) string {
17 return path
20 // file is the real representation of *File.
21 // The extra level of indirection ensures that no clients of os
22 // can overwrite this data, which could cause the finalizer
23 // to close the wrong file descriptor.
24 type file struct {
25 fd int
26 name string
27 dirinfo *dirInfo // nil unless directory being read
28 appendMode bool // whether file is opened for appending
31 // Fd returns the integer Plan 9 file descriptor referencing the open file.
32 // If f is closed, the file descriptor becomes invalid.
33 // If f is garbage collected, a finalizer may close the file descriptor,
34 // making it invalid; see runtime.SetFinalizer for more information on when
35 // a finalizer might be run. On Unix systems this will cause the SetDeadline
36 // methods to stop working.
38 // As an alternative, see the f.SyscallConn method.
39 func (f *File) Fd() uintptr {
40 if f == nil {
41 return ^(uintptr(0))
43 return uintptr(f.fd)
46 // NewFile returns a new File with the given file descriptor and
47 // name. The returned value will be nil if fd is not a valid file
48 // descriptor.
49 func NewFile(fd uintptr, name string) *File {
50 fdi := int(fd)
51 if fdi < 0 {
52 return nil
54 f := &File{&file{fd: fdi, name: name}}
55 runtime.SetFinalizer(f.file, (*file).close)
56 return f
59 // Auxiliary information if the File describes a directory
60 type dirInfo struct {
61 buf [syscall.STATMAX]byte // buffer for directory I/O
62 nbuf int // length of buf; return value from Read
63 bufp int // location of next record in buf.
66 func epipecheck(file *File, e error) {
69 // DevNull is the name of the operating system's ``null device.''
70 // On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
71 const DevNull = "/dev/null"
73 // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
74 func syscallMode(i FileMode) (o uint32) {
75 o |= uint32(i.Perm())
76 if i&ModeAppend != 0 {
77 o |= syscall.DMAPPEND
79 if i&ModeExclusive != 0 {
80 o |= syscall.DMEXCL
82 if i&ModeTemporary != 0 {
83 o |= syscall.DMTMP
85 return
88 // openFileNolog is the Plan 9 implementation of OpenFile.
89 func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
90 var (
91 fd int
92 e error
93 create bool
94 excl bool
95 trunc bool
96 append bool
99 if flag&O_CREATE == O_CREATE {
100 flag = flag & ^O_CREATE
101 create = true
103 if flag&O_EXCL == O_EXCL {
104 excl = true
106 if flag&O_TRUNC == O_TRUNC {
107 trunc = true
109 // O_APPEND is emulated on Plan 9
110 if flag&O_APPEND == O_APPEND {
111 flag = flag &^ O_APPEND
112 append = true
115 if (create && trunc) || excl {
116 fd, e = syscall.Create(name, flag, syscallMode(perm))
117 } else {
118 fd, e = syscall.Open(name, flag)
119 if IsNotExist(e) && create {
120 fd, e = syscall.Create(name, flag, syscallMode(perm))
121 if e != nil {
122 return nil, &PathError{Op: "create", Path: name, Err: e}
127 if e != nil {
128 return nil, &PathError{Op: "open", Path: name, Err: e}
131 if append {
132 if _, e = syscall.Seek(fd, 0, io.SeekEnd); e != nil {
133 return nil, &PathError{Op: "seek", Path: name, Err: e}
137 return NewFile(uintptr(fd), name), nil
140 // Close closes the File, rendering it unusable for I/O.
141 // On files that support SetDeadline, any pending I/O operations will
142 // be canceled and return immediately with an ErrClosed error.
143 // Close will return an error if it has already been called.
144 func (f *File) Close() error {
145 if err := f.checkValid("close"); err != nil {
146 return err
148 return f.file.close()
151 func (file *file) close() error {
152 if file == nil || file.fd == badFd {
153 return ErrInvalid
155 var err error
156 if e := syscall.Close(file.fd); e != nil {
157 err = &PathError{Op: "close", Path: file.name, Err: e}
159 file.fd = badFd // so it can't be closed again
161 // no need for a finalizer anymore
162 runtime.SetFinalizer(file, nil)
163 return err
166 // Stat returns the FileInfo structure describing file.
167 // If there is an error, it will be of type *PathError.
168 func (f *File) Stat() (FileInfo, error) {
169 if f == nil {
170 return nil, ErrInvalid
172 d, err := dirstat(f)
173 if err != nil {
174 return nil, err
176 return fileInfoFromStat(d), nil
179 // Truncate changes the size of the file.
180 // It does not change the I/O offset.
181 // If there is an error, it will be of type *PathError.
182 func (f *File) Truncate(size int64) error {
183 if f == nil {
184 return ErrInvalid
187 var d syscall.Dir
188 d.Null()
189 d.Length = size
191 var buf [syscall.STATFIXLEN]byte
192 n, err := d.Marshal(buf[:])
193 if err != nil {
194 return &PathError{Op: "truncate", Path: f.name, Err: err}
196 if err = syscall.Fwstat(f.fd, buf[:n]); err != nil {
197 return &PathError{Op: "truncate", Path: f.name, Err: err}
199 return nil
202 const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm)
204 func (f *File) chmod(mode FileMode) error {
205 if f == nil {
206 return ErrInvalid
208 var d syscall.Dir
210 odir, e := dirstat(f)
211 if e != nil {
212 return &PathError{Op: "chmod", Path: f.name, Err: e}
214 d.Null()
215 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
217 var buf [syscall.STATFIXLEN]byte
218 n, err := d.Marshal(buf[:])
219 if err != nil {
220 return &PathError{Op: "chmod", Path: f.name, Err: err}
222 if err = syscall.Fwstat(f.fd, buf[:n]); err != nil {
223 return &PathError{Op: "chmod", Path: f.name, Err: err}
225 return nil
228 // Sync commits the current contents of the file to stable storage.
229 // Typically, this means flushing the file system's in-memory copy
230 // of recently written data to disk.
231 func (f *File) Sync() error {
232 if f == nil {
233 return ErrInvalid
235 var d syscall.Dir
236 d.Null()
238 var buf [syscall.STATFIXLEN]byte
239 n, err := d.Marshal(buf[:])
240 if err != nil {
241 return &PathError{Op: "sync", Path: f.name, Err: err}
243 if err = syscall.Fwstat(f.fd, buf[:n]); err != nil {
244 return &PathError{Op: "sync", Path: f.name, Err: err}
246 return nil
249 // read reads up to len(b) bytes from the File.
250 // It returns the number of bytes read and an error, if any.
251 func (f *File) read(b []byte) (n int, err error) {
252 n, e := fixCount(syscall.Read(f.fd, b))
253 if n == 0 && len(b) > 0 && e == nil {
254 return 0, io.EOF
256 return n, e
259 // pread reads len(b) bytes from the File starting at byte offset off.
260 // It returns the number of bytes read and the error, if any.
261 // EOF is signaled by a zero count with err set to nil.
262 func (f *File) pread(b []byte, off int64) (n int, err error) {
263 n, e := fixCount(syscall.Pread(f.fd, b, off))
264 if n == 0 && len(b) > 0 && e == nil {
265 return 0, io.EOF
267 return n, e
270 // write writes len(b) bytes to the File.
271 // It returns the number of bytes written and an error, if any.
272 // Since Plan 9 preserves message boundaries, never allow
273 // a zero-byte write.
274 func (f *File) write(b []byte) (n int, err error) {
275 if len(b) == 0 {
276 return 0, nil
278 return fixCount(syscall.Write(f.fd, b))
281 // pwrite writes len(b) bytes to the File starting at byte offset off.
282 // It returns the number of bytes written and an error, if any.
283 // Since Plan 9 preserves message boundaries, never allow
284 // a zero-byte write.
285 func (f *File) pwrite(b []byte, off int64) (n int, err error) {
286 if len(b) == 0 {
287 return 0, nil
289 return fixCount(syscall.Pwrite(f.fd, b, off))
292 // seek sets the offset for the next Read or Write on file to offset, interpreted
293 // according to whence: 0 means relative to the origin of the file, 1 means
294 // relative to the current offset, and 2 means relative to the end.
295 // It returns the new offset and an error, if any.
296 func (f *File) seek(offset int64, whence int) (ret int64, err error) {
297 if f.dirinfo != nil {
298 // Free cached dirinfo, so we allocate a new one if we
299 // access this file as a directory again. See #35767 and #37161.
300 f.dirinfo = nil
302 return syscall.Seek(f.fd, offset, whence)
305 // Truncate changes the size of the named file.
306 // If the file is a symbolic link, it changes the size of the link's target.
307 // If there is an error, it will be of type *PathError.
308 func Truncate(name string, size int64) error {
309 var d syscall.Dir
311 d.Null()
312 d.Length = size
314 var buf [syscall.STATFIXLEN]byte
315 n, err := d.Marshal(buf[:])
316 if err != nil {
317 return &PathError{Op: "truncate", Path: name, Err: err}
319 if err = syscall.Wstat(name, buf[:n]); err != nil {
320 return &PathError{Op: "truncate", Path: name, Err: err}
322 return nil
325 // Remove removes the named file or directory.
326 // If there is an error, it will be of type *PathError.
327 func Remove(name string) error {
328 if e := syscall.Remove(name); e != nil {
329 return &PathError{Op: "remove", Path: name, Err: e}
331 return nil
334 // HasPrefix from the strings package.
335 func hasPrefix(s, prefix string) bool {
336 return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
339 func rename(oldname, newname string) error {
340 dirname := oldname[:lastIndex(oldname, '/')+1]
341 if hasPrefix(newname, dirname) {
342 newname = newname[len(dirname):]
343 } else {
344 return &LinkError{"rename", oldname, newname, ErrInvalid}
347 // If newname still contains slashes after removing the oldname
348 // prefix, the rename is cross-directory and must be rejected.
349 if lastIndex(newname, '/') >= 0 {
350 return &LinkError{"rename", oldname, newname, ErrInvalid}
353 var d syscall.Dir
355 d.Null()
356 d.Name = newname
358 buf := make([]byte, syscall.STATFIXLEN+len(d.Name))
359 n, err := d.Marshal(buf[:])
360 if err != nil {
361 return &LinkError{"rename", oldname, newname, err}
364 // If newname already exists and is not a directory, rename replaces it.
365 f, err := Stat(dirname + newname)
366 if err == nil && !f.IsDir() {
367 Remove(dirname + newname)
370 if err = syscall.Wstat(oldname, buf[:n]); err != nil {
371 return &LinkError{"rename", oldname, newname, err}
373 return nil
376 // See docs in file.go:Chmod.
377 func chmod(name string, mode FileMode) error {
378 var d syscall.Dir
380 odir, e := dirstat(name)
381 if e != nil {
382 return &PathError{Op: "chmod", Path: name, Err: e}
384 d.Null()
385 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
387 var buf [syscall.STATFIXLEN]byte
388 n, err := d.Marshal(buf[:])
389 if err != nil {
390 return &PathError{Op: "chmod", Path: name, Err: err}
392 if err = syscall.Wstat(name, buf[:n]); err != nil {
393 return &PathError{Op: "chmod", Path: name, Err: err}
395 return nil
398 // Chtimes changes the access and modification times of the named
399 // file, similar to the Unix utime() or utimes() functions.
401 // The underlying filesystem may truncate or round the values to a
402 // less precise time unit.
403 // If there is an error, it will be of type *PathError.
404 func Chtimes(name string, atime time.Time, mtime time.Time) error {
405 var d syscall.Dir
407 d.Null()
408 d.Atime = uint32(atime.Unix())
409 d.Mtime = uint32(mtime.Unix())
411 var buf [syscall.STATFIXLEN]byte
412 n, err := d.Marshal(buf[:])
413 if err != nil {
414 return &PathError{Op: "chtimes", Path: name, Err: err}
416 if err = syscall.Wstat(name, buf[:n]); err != nil {
417 return &PathError{Op: "chtimes", Path: name, Err: err}
419 return nil
422 // Pipe returns a connected pair of Files; reads from r return bytes
423 // written to w. It returns the files and an error, if any.
424 func Pipe() (r *File, w *File, err error) {
425 var p [2]int
427 if e := syscall.Pipe(p[0:]); e != nil {
428 return nil, nil, NewSyscallError("pipe", e)
431 return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
434 // not supported on Plan 9
436 // Link creates newname as a hard link to the oldname file.
437 // If there is an error, it will be of type *LinkError.
438 func Link(oldname, newname string) error {
439 return &LinkError{"link", oldname, newname, syscall.EPLAN9}
442 // Symlink creates newname as a symbolic link to oldname.
443 // On Windows, a symlink to a non-existent oldname creates a file symlink;
444 // if oldname is later created as a directory the symlink will not work.
445 // If there is an error, it will be of type *LinkError.
446 func Symlink(oldname, newname string) error {
447 return &LinkError{"symlink", oldname, newname, syscall.EPLAN9}
450 // Readlink returns the destination of the named symbolic link.
451 // If there is an error, it will be of type *PathError.
452 func Readlink(name string) (string, error) {
453 return "", &PathError{Op: "readlink", Path: name, Err: syscall.EPLAN9}
456 // Chown changes the numeric uid and gid of the named file.
457 // If the file is a symbolic link, it changes the uid and gid of the link's target.
458 // A uid or gid of -1 means to not change that value.
459 // If there is an error, it will be of type *PathError.
461 // On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or
462 // EPLAN9 error, wrapped in *PathError.
463 func Chown(name string, uid, gid int) error {
464 return &PathError{Op: "chown", Path: name, Err: syscall.EPLAN9}
467 // Lchown changes the numeric uid and gid of the named file.
468 // If the file is a symbolic link, it changes the uid and gid of the link itself.
469 // If there is an error, it will be of type *PathError.
470 func Lchown(name string, uid, gid int) error {
471 return &PathError{Op: "lchown", Path: name, Err: syscall.EPLAN9}
474 // Chown changes the numeric uid and gid of the named file.
475 // If there is an error, it will be of type *PathError.
476 func (f *File) Chown(uid, gid int) error {
477 if f == nil {
478 return ErrInvalid
480 return &PathError{Op: "chown", Path: f.name, Err: syscall.EPLAN9}
483 func tempDir() string {
484 dir := Getenv("TMPDIR")
485 if dir == "" {
486 dir = "/tmp"
488 return dir
492 // Chdir changes the current working directory to the file,
493 // which must be a directory.
494 // If there is an error, it will be of type *PathError.
495 func (f *File) Chdir() error {
496 if err := f.checkValid("chdir"); err != nil {
497 return err
499 if e := syscall.Fchdir(f.fd); e != nil {
500 return &PathError{Op: "chdir", Path: f.name, Err: e}
502 return nil
505 // setDeadline sets the read and write deadline.
506 func (f *File) setDeadline(time.Time) error {
507 if err := f.checkValid("SetDeadline"); err != nil {
508 return err
510 return poll.ErrNoDeadline
513 // setReadDeadline sets the read deadline.
514 func (f *File) setReadDeadline(time.Time) error {
515 if err := f.checkValid("SetReadDeadline"); err != nil {
516 return err
518 return poll.ErrNoDeadline
521 // setWriteDeadline sets the write deadline.
522 func (f *File) setWriteDeadline(time.Time) error {
523 if err := f.checkValid("SetWriteDeadline"); err != nil {
524 return err
526 return poll.ErrNoDeadline
529 // checkValid checks whether f is valid for use.
530 // If not, it returns an appropriate error, perhaps incorporating the operation name op.
531 func (f *File) checkValid(op string) error {
532 if f == nil {
533 return ErrInvalid
535 if f.fd == badFd {
536 return &PathError{Op: op, Path: f.name, Err: ErrClosed}
538 return nil
541 type rawConn struct{}
543 func (c *rawConn) Control(f func(uintptr)) error {
544 return syscall.EPLAN9
547 func (c *rawConn) Read(f func(uintptr) bool) error {
548 return syscall.EPLAN9
551 func (c *rawConn) Write(f func(uintptr) bool) error {
552 return syscall.EPLAN9
555 func newRawConn(file *File) (*rawConn, error) {
556 return nil, syscall.EPLAN9
559 func ignoringEINTR(fn func() error) error {
560 return fn()