file_unix.go 9.61 KB
Newer Older
1 2 3 4
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

5
// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
6

7 8 9
package os

import (
10
	"internal/poll"
11 12 13 14
	"runtime"
	"syscall"
)

15 16 17
// fixLongPath is a noop on non-Windows platforms.
func fixLongPath(path string) string {
	return path
18 19
}

20
func rename(oldname, newname string) error {
21 22
	fi, err := Lstat(newname)
	if err == nil && fi.IsDir() {
23 24 25 26 27 28 29 30 31 32 33
		// There are two independent errors this function can return:
		// one for a bad oldname, and one for a bad newname.
		// At this point we've determined the newname is bad.
		// But just in case oldname is also bad, prioritize returning
		// the oldname error because that's what we did historically.
		if _, err := Lstat(oldname); err != nil {
			if pe, ok := err.(*PathError); ok {
				err = pe.Err
			}
			return &LinkError{"rename", oldname, newname, err}
		}
34 35
		return &LinkError{"rename", oldname, newname, syscall.EEXIST}
	}
36 37 38
	err = syscall.Rename(oldname, newname)
	if err != nil {
		return &LinkError{"rename", oldname, newname, err}
39 40 41 42
	}
	return nil
}

43 44 45 46 47
// file is the real representation of *File.
// The extra level of indirection ensures that no clients of os
// can overwrite this data, which could cause the finalizer
// to close the wrong file descriptor.
type file struct {
48 49 50 51 52
	pfd         poll.FD
	name        string
	dirinfo     *dirInfo // nil unless directory being read
	nonblock    bool     // whether we set nonblocking mode
	stdoutOrErr bool     // whether this is stdout or stderr
53 54 55
}

// Fd returns the integer Unix file descriptor referencing the open file.
56
// The file descriptor is valid only until f.Close is called or f is garbage collected.
57
// On Unix systems this will cause the SetDeadline methods to stop working.
58
func (f *File) Fd() uintptr {
59
	if f == nil {
60
		return ^(uintptr(0))
61
	}
62 63 64 65 66 67 68

	// If we put the file descriptor into nonblocking mode,
	// then set it to blocking mode before we return it,
	// because historically we have always returned a descriptor
	// opened in blocking mode. The File will continue to work,
	// but any blocking operation will tie up a thread.
	if f.nonblock {
69
		f.pfd.SetBlocking()
70 71 72
	}

	return uintptr(f.pfd.Sysfd)
73 74
}

75 76 77
// NewFile returns a new File with the given file descriptor and
// name. The returned value will be nil if fd is not a valid file
// descriptor.
78
func NewFile(fd uintptr, name string) *File {
79
	return newFile(fd, name, kindNewFile)
80 81
}

82 83 84 85 86 87 88 89 90 91 92 93 94
// newFileKind describes the kind of file to newFile.
type newFileKind int

const (
	kindNewFile newFileKind = iota
	kindOpenFile
	kindPipe
)

// newFile is like NewFile, but if called from OpenFile or Pipe
// (as passed in the kind parameter) it tries to add the file to
// the runtime poller.
func newFile(fd uintptr, name string, kind newFileKind) *File {
95 96
	fdi := int(fd)
	if fdi < 0 {
97 98
		return nil
	}
99 100 101 102 103 104
	f := &File{&file{
		pfd: poll.FD{
			Sysfd:         fdi,
			IsStream:      true,
			ZeroReadIsEOF: true,
		},
105 106
		name:        name,
		stdoutOrErr: fdi == 1 || fdi == 2,
107 108 109 110 111
	}}

	// Don't try to use kqueue with regular files on FreeBSD.
	// It crashes the system unpredictably while running all.bash.
	// Issue 19093.
112 113
	if runtime.GOOS == "freebsd" && kind == kindOpenFile {
		kind = kindNewFile
114 115
	}

116
	pollable := kind == kindOpenFile || kind == kindPipe
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
	if err := f.pfd.Init("file", pollable); err != nil {
		// An error here indicates a failure to register
		// with the netpoll system. That can happen for
		// a file descriptor that is not supported by
		// epoll/kqueue; for example, disk files on
		// GNU/Linux systems. We assume that any real error
		// will show up in later I/O.
	} else if pollable {
		// We successfully registered with netpoll, so put
		// the file into nonblocking mode.
		if err := syscall.SetNonblock(fdi, true); err == nil {
			f.nonblock = true
		}
	}

132
	runtime.SetFinalizer(f.file, (*file).close)
133 134 135
	return f
}

136 137
// Auxiliary information if the File describes a directory
type dirInfo struct {
138
	buf []byte       // buffer for directory I/O
139 140 141
	dir *syscall.DIR // from opendir
}

142 143 144
// epipecheck raises SIGPIPE if we get an EPIPE error on standard
// output or standard error. See the SIGPIPE docs in os/signal, and
// issue 11845.
145
func epipecheck(file *File, e error) {
146
	if e == syscall.EPIPE && file.stdoutOrErr {
147
		sigpipe()
148 149 150
	}
}

151 152 153 154
// DevNull is the name of the operating system's ``null device.''
// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
const DevNull = "/dev/null"

155 156
// openFileNolog is the Unix implementation of OpenFile.
func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
157 158 159 160 161 162 163
	chmod := false
	if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
		if _, err := Stat(name); IsNotExist(err) {
			chmod = true
		}
	}

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
	var r int
	for {
		var e error
		r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
		if e == nil {
			break
		}

		// On OS X, sigaction(2) doesn't guarantee that SA_RESTART will cause
		// open(2) to be restarted for regular files. This is easy to reproduce on
		// fuse file systems (see http://golang.org/issue/11180).
		if runtime.GOOS == "darwin" && e == syscall.EINTR {
			continue
		}

179
		return nil, &PathError{"open", name, e}
180 181
	}

182 183 184 185 186
	// open(2) itself won't handle the sticky bit on *BSD and Solaris
	if chmod {
		Chmod(name, perm)
	}

187
	// There's a race here with fork/exec, which we are
188
	// content to live with. See ../syscall/exec_unix.go.
189
	if !supportsCloseOnExec {
190 191 192
		syscall.CloseOnExec(r)
	}

193
	return newFile(uintptr(r), name, kindOpenFile), nil
194 195 196
}

// Close closes the File, rendering it unusable for I/O.
197
// It returns an error, if any.
198
func (f *File) Close() error {
199 200 201
	if f == nil {
		return ErrInvalid
	}
202
	return f.file.close()
203 204 205
}

func (file *file) close() error {
206
	if file == nil {
207
		return syscall.EINVAL
208
	}
209
	var err error
210 211 212 213
	if e := file.pfd.Close(); e != nil {
		if e == poll.ErrFileClosing {
			e = ErrClosed
		}
214
		err = &PathError{"close", file.name, e}
215
	}
216 217

	if file.dirinfo != nil {
218 219 220 221 222 223 224
		syscall.Entersyscall()
		i := libc_closedir(file.dirinfo.dir)
		errno := syscall.GetErrno()
		syscall.Exitsyscall()
		file.dirinfo = nil
		if i < 0 && err == nil {
			err = &PathError{"closedir", file.name, errno}
225 226 227
		}
	}

228 229 230 231 232
	// no need for a finalizer anymore
	runtime.SetFinalizer(file, nil)
	return err
}

233 234
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
235
func (f *File) read(b []byte) (n int, err error) {
236 237 238
	n, err = f.pfd.Read(b)
	runtime.KeepAlive(f)
	return n, err
239 240 241 242
}

// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
243
// EOF is signaled by a zero count with err set to nil.
244
func (f *File) pread(b []byte, off int64) (n int, err error) {
245 246 247
	n, err = f.pfd.Pread(b, off)
	runtime.KeepAlive(f)
	return n, err
248 249 250 251
}

// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
252
func (f *File) write(b []byte) (n int, err error) {
253 254 255
	n, err = f.pfd.Write(b)
	runtime.KeepAlive(f)
	return n, err
256 257 258 259
}

// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
260
func (f *File) pwrite(b []byte, off int64) (n int, err error) {
261 262 263
	n, err = f.pfd.Pwrite(b, off)
	runtime.KeepAlive(f)
	return n, err
264 265 266 267 268 269
}

// seek sets the offset for the next Read or Write on file to offset, interpreted
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
// It returns the new offset and an error, if any.
270
func (f *File) seek(offset int64, whence int) (ret int64, err error) {
271 272 273
	ret, err = f.pfd.Seek(offset, whence)
	runtime.KeepAlive(f)
	return ret, err
274 275
}

276 277
// Truncate changes the size of the named file.
// If the file is a symbolic link, it changes the size of the link's target.
278
// If there is an error, it will be of type *PathError.
279
func Truncate(name string, size int64) error {
280 281
	if e := syscall.Truncate(name, size); e != nil {
		return &PathError{"truncate", name, e}
282 283 284
	}
	return nil
}
285

286
// Remove removes the named file or directory.
287
// If there is an error, it will be of type *PathError.
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
func Remove(name string) error {
	// System call interface forces us to know
	// whether name is a file or directory.
	// Try both: it is cheaper on average than
	// doing a Stat plus the right one.
	e := syscall.Unlink(name)
	if e == nil {
		return nil
	}
	e1 := syscall.Rmdir(name)
	if e1 == nil {
		return nil
	}

	// Both failed: figure out which error to return.
	// OS X and Linux differ on whether unlink(dir)
304
	// returns EISDIR, so can't use that. However,
305 306 307 308 309 310 311 312 313 314 315 316
	// both agree that rmdir(file) returns ENOTDIR,
	// so we can use that to decide which error is real.
	// Rmdir might also return ENOTDIR if given a bad
	// file path, like /etc/passwd/foo, but in that case,
	// both errors will be ENOTDIR, so it's okay to
	// use the error from unlink.
	if e1 != syscall.ENOTDIR {
		e = e1
	}
	return &PathError{"remove", name, e}
}

317
func tempDir() string {
318 319
	dir := Getenv("TMPDIR")
	if dir == "" {
320 321 322 323 324
		if runtime.GOOS == "android" {
			dir = "/data/local/tmp"
		} else {
			dir = "/tmp"
		}
325 326 327
	}
	return dir
}
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347

// Link creates newname as a hard link to the oldname file.
// If there is an error, it will be of type *LinkError.
func Link(oldname, newname string) error {
	e := syscall.Link(oldname, newname)
	if e != nil {
		return &LinkError{"link", oldname, newname, e}
	}
	return nil
}

// Symlink creates newname as a symbolic link to oldname.
// If there is an error, it will be of type *LinkError.
func Symlink(oldname, newname string) error {
	e := syscall.Symlink(oldname, newname)
	if e != nil {
		return &LinkError{"symlink", oldname, newname, e}
	}
	return nil
}