| 1 |
747 |
jeremybenn |
// Copyright 2009 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.
|
| 4 |
|
|
|
| 5 |
|
|
// +build darwin freebsd linux netbsd openbsd
|
| 6 |
|
|
|
| 7 |
|
|
package os
|
| 8 |
|
|
|
| 9 |
|
|
import (
|
| 10 |
|
|
"runtime"
|
| 11 |
|
|
"syscall"
|
| 12 |
|
|
)
|
| 13 |
|
|
|
| 14 |
|
|
// File represents an open file descriptor.
|
| 15 |
|
|
type File struct {
|
| 16 |
|
|
*file
|
| 17 |
|
|
}
|
| 18 |
|
|
|
| 19 |
|
|
// file is the real representation of *File.
|
| 20 |
|
|
// The extra level of indirection ensures that no clients of os
|
| 21 |
|
|
// can overwrite this data, which could cause the finalizer
|
| 22 |
|
|
// to close the wrong file descriptor.
|
| 23 |
|
|
type file struct {
|
| 24 |
|
|
fd int
|
| 25 |
|
|
name string
|
| 26 |
|
|
dirinfo *dirInfo // nil unless directory being read
|
| 27 |
|
|
nepipe int // number of consecutive EPIPE in Write
|
| 28 |
|
|
}
|
| 29 |
|
|
|
| 30 |
|
|
// Fd returns the integer Unix file descriptor referencing the open file.
|
| 31 |
|
|
func (f *File) Fd() int {
|
| 32 |
|
|
if f == nil {
|
| 33 |
|
|
return -1
|
| 34 |
|
|
}
|
| 35 |
|
|
return f.fd
|
| 36 |
|
|
}
|
| 37 |
|
|
|
| 38 |
|
|
// NewFile returns a new File with the given file descriptor and name.
|
| 39 |
|
|
func NewFile(fd int, name string) *File {
|
| 40 |
|
|
if fd < 0 {
|
| 41 |
|
|
return nil
|
| 42 |
|
|
}
|
| 43 |
|
|
f := &File{&file{fd: fd, name: name}}
|
| 44 |
|
|
runtime.SetFinalizer(f.file, (*file).close)
|
| 45 |
|
|
return f
|
| 46 |
|
|
}
|
| 47 |
|
|
|
| 48 |
|
|
// Auxiliary information if the File describes a directory
|
| 49 |
|
|
type dirInfo struct {
|
| 50 |
|
|
buf []byte // buffer for directory I/O
|
| 51 |
|
|
dir *syscall.DIR // from opendir
|
| 52 |
|
|
}
|
| 53 |
|
|
|
| 54 |
|
|
// DevNull is the name of the operating system's ``null device.''
|
| 55 |
|
|
// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
|
| 56 |
|
|
const DevNull = "/dev/null"
|
| 57 |
|
|
|
| 58 |
|
|
// OpenFile is the generalized open call; most users will use Open
|
| 59 |
|
|
// or Create instead. It opens the named file with specified flag
|
| 60 |
|
|
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
|
| 61 |
|
|
// methods on the returned File can be used for I/O.
|
| 62 |
|
|
// It returns the File and an error, if any.
|
| 63 |
|
|
func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
|
| 64 |
|
|
r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
|
| 65 |
|
|
if e != nil {
|
| 66 |
|
|
return nil, &PathError{"open", name, e}
|
| 67 |
|
|
}
|
| 68 |
|
|
|
| 69 |
|
|
// There's a race here with fork/exec, which we are
|
| 70 |
|
|
// content to live with. See ../syscall/exec_unix.go.
|
| 71 |
|
|
// On OS X 10.6, the O_CLOEXEC flag is not respected.
|
| 72 |
|
|
// On OS X 10.7, the O_CLOEXEC flag works.
|
| 73 |
|
|
// Without a cheap & reliable way to detect 10.6 vs 10.7 at
|
| 74 |
|
|
// runtime, we just always call syscall.CloseOnExec on Darwin.
|
| 75 |
|
|
// Once >=10.7 is prevalent, this extra call can removed.
|
| 76 |
|
|
if syscall.O_CLOEXEC == 0 || runtime.GOOS == "darwin" { // O_CLOEXEC not supported
|
| 77 |
|
|
syscall.CloseOnExec(r)
|
| 78 |
|
|
}
|
| 79 |
|
|
|
| 80 |
|
|
return NewFile(r, name), nil
|
| 81 |
|
|
}
|
| 82 |
|
|
|
| 83 |
|
|
// Close closes the File, rendering it unusable for I/O.
|
| 84 |
|
|
// It returns an error, if any.
|
| 85 |
|
|
func (f *File) Close() error {
|
| 86 |
|
|
return f.file.close()
|
| 87 |
|
|
}
|
| 88 |
|
|
|
| 89 |
|
|
func (file *file) close() error {
|
| 90 |
|
|
if file == nil || file.fd < 0 {
|
| 91 |
|
|
return EINVAL
|
| 92 |
|
|
}
|
| 93 |
|
|
var err error
|
| 94 |
|
|
if e := syscall.Close(file.fd); e != nil {
|
| 95 |
|
|
err = &PathError{"close", file.name, e}
|
| 96 |
|
|
}
|
| 97 |
|
|
|
| 98 |
|
|
if file.dirinfo != nil {
|
| 99 |
|
|
if libc_closedir(file.dirinfo.dir) < 0 && err == nil {
|
| 100 |
|
|
err = &PathError{"closedir", file.name, syscall.GetErrno()}
|
| 101 |
|
|
}
|
| 102 |
|
|
}
|
| 103 |
|
|
|
| 104 |
|
|
file.fd = -1 // so it can't be closed again
|
| 105 |
|
|
|
| 106 |
|
|
// no need for a finalizer anymore
|
| 107 |
|
|
runtime.SetFinalizer(file, nil)
|
| 108 |
|
|
return err
|
| 109 |
|
|
}
|
| 110 |
|
|
|
| 111 |
|
|
// Stat returns the FileInfo structure describing file.
|
| 112 |
|
|
// It returns the FileInfo and an error, if any.
|
| 113 |
|
|
func (f *File) Stat() (fi FileInfo, err error) {
|
| 114 |
|
|
var stat syscall.Stat_t
|
| 115 |
|
|
err = syscall.Fstat(f.fd, &stat)
|
| 116 |
|
|
if err != nil {
|
| 117 |
|
|
return nil, &PathError{"stat", f.name, err}
|
| 118 |
|
|
}
|
| 119 |
|
|
return fileInfoFromStat(&stat, f.name), nil
|
| 120 |
|
|
}
|
| 121 |
|
|
|
| 122 |
|
|
// Stat returns a FileInfo describing the named file and an error, if any.
|
| 123 |
|
|
// If name names a valid symbolic link, the returned FileInfo describes
|
| 124 |
|
|
// the file pointed at by the link and has fi.FollowedSymlink set to true.
|
| 125 |
|
|
// If name names an invalid symbolic link, the returned FileInfo describes
|
| 126 |
|
|
// the link itself and has fi.FollowedSymlink set to false.
|
| 127 |
|
|
func Stat(name string) (fi FileInfo, err error) {
|
| 128 |
|
|
var stat syscall.Stat_t
|
| 129 |
|
|
err = syscall.Stat(name, &stat)
|
| 130 |
|
|
if err != nil {
|
| 131 |
|
|
return nil, &PathError{"stat", name, err}
|
| 132 |
|
|
}
|
| 133 |
|
|
return fileInfoFromStat(&stat, name), nil
|
| 134 |
|
|
}
|
| 135 |
|
|
|
| 136 |
|
|
// Lstat returns a FileInfo describing the named file and an
|
| 137 |
|
|
// error, if any. If the file is a symbolic link, the returned FileInfo
|
| 138 |
|
|
// describes the symbolic link. Lstat makes no attempt to follow the link.
|
| 139 |
|
|
func Lstat(name string) (fi FileInfo, err error) {
|
| 140 |
|
|
var stat syscall.Stat_t
|
| 141 |
|
|
err = syscall.Lstat(name, &stat)
|
| 142 |
|
|
if err != nil {
|
| 143 |
|
|
return nil, &PathError{"lstat", name, err}
|
| 144 |
|
|
}
|
| 145 |
|
|
return fileInfoFromStat(&stat, name), nil
|
| 146 |
|
|
}
|
| 147 |
|
|
|
| 148 |
|
|
func (f *File) readdir(n int) (fi []FileInfo, err error) {
|
| 149 |
|
|
dirname := f.name
|
| 150 |
|
|
if dirname == "" {
|
| 151 |
|
|
dirname = "."
|
| 152 |
|
|
}
|
| 153 |
|
|
dirname += "/"
|
| 154 |
|
|
names, err := f.Readdirnames(n)
|
| 155 |
|
|
fi = make([]FileInfo, len(names))
|
| 156 |
|
|
for i, filename := range names {
|
| 157 |
|
|
fip, err := Lstat(dirname + filename)
|
| 158 |
|
|
if err == nil {
|
| 159 |
|
|
fi[i] = fip
|
| 160 |
|
|
} else {
|
| 161 |
|
|
fi[i] = &fileStat{name: filename}
|
| 162 |
|
|
}
|
| 163 |
|
|
}
|
| 164 |
|
|
return fi, err
|
| 165 |
|
|
}
|
| 166 |
|
|
|
| 167 |
|
|
// read reads up to len(b) bytes from the File.
|
| 168 |
|
|
// It returns the number of bytes read and an error, if any.
|
| 169 |
|
|
func (f *File) read(b []byte) (n int, err error) {
|
| 170 |
|
|
return syscall.Read(f.fd, b)
|
| 171 |
|
|
}
|
| 172 |
|
|
|
| 173 |
|
|
// pread reads len(b) bytes from the File starting at byte offset off.
|
| 174 |
|
|
// It returns the number of bytes read and the error, if any.
|
| 175 |
|
|
// EOF is signaled by a zero count with err set to 0.
|
| 176 |
|
|
func (f *File) pread(b []byte, off int64) (n int, err error) {
|
| 177 |
|
|
return syscall.Pread(f.fd, b, off)
|
| 178 |
|
|
}
|
| 179 |
|
|
|
| 180 |
|
|
// write writes len(b) bytes to the File.
|
| 181 |
|
|
// It returns the number of bytes written and an error, if any.
|
| 182 |
|
|
func (f *File) write(b []byte) (n int, err error) {
|
| 183 |
|
|
return syscall.Write(f.fd, b)
|
| 184 |
|
|
}
|
| 185 |
|
|
|
| 186 |
|
|
// pwrite writes len(b) bytes to the File starting at byte offset off.
|
| 187 |
|
|
// It returns the number of bytes written and an error, if any.
|
| 188 |
|
|
func (f *File) pwrite(b []byte, off int64) (n int, err error) {
|
| 189 |
|
|
return syscall.Pwrite(f.fd, b, off)
|
| 190 |
|
|
}
|
| 191 |
|
|
|
| 192 |
|
|
// seek sets the offset for the next Read or Write on file to offset, interpreted
|
| 193 |
|
|
// according to whence: 0 means relative to the origin of the file, 1 means
|
| 194 |
|
|
// relative to the current offset, and 2 means relative to the end.
|
| 195 |
|
|
// It returns the new offset and an error, if any.
|
| 196 |
|
|
func (f *File) seek(offset int64, whence int) (ret int64, err error) {
|
| 197 |
|
|
return syscall.Seek(f.fd, offset, whence)
|
| 198 |
|
|
}
|
| 199 |
|
|
|
| 200 |
|
|
// Truncate changes the size of the named file.
|
| 201 |
|
|
// If the file is a symbolic link, it changes the size of the link's target.
|
| 202 |
|
|
func Truncate(name string, size int64) error {
|
| 203 |
|
|
if e := syscall.Truncate(name, size); e != nil {
|
| 204 |
|
|
return &PathError{"truncate", name, e}
|
| 205 |
|
|
}
|
| 206 |
|
|
return nil
|
| 207 |
|
|
}
|
| 208 |
|
|
|
| 209 |
|
|
// Remove removes the named file or directory.
|
| 210 |
|
|
func Remove(name string) error {
|
| 211 |
|
|
// System call interface forces us to know
|
| 212 |
|
|
// whether name is a file or directory.
|
| 213 |
|
|
// Try both: it is cheaper on average than
|
| 214 |
|
|
// doing a Stat plus the right one.
|
| 215 |
|
|
e := syscall.Unlink(name)
|
| 216 |
|
|
if e == nil {
|
| 217 |
|
|
return nil
|
| 218 |
|
|
}
|
| 219 |
|
|
e1 := syscall.Rmdir(name)
|
| 220 |
|
|
if e1 == nil {
|
| 221 |
|
|
return nil
|
| 222 |
|
|
}
|
| 223 |
|
|
|
| 224 |
|
|
// Both failed: figure out which error to return.
|
| 225 |
|
|
// OS X and Linux differ on whether unlink(dir)
|
| 226 |
|
|
// returns EISDIR, so can't use that. However,
|
| 227 |
|
|
// both agree that rmdir(file) returns ENOTDIR,
|
| 228 |
|
|
// so we can use that to decide which error is real.
|
| 229 |
|
|
// Rmdir might also return ENOTDIR if given a bad
|
| 230 |
|
|
// file path, like /etc/passwd/foo, but in that case,
|
| 231 |
|
|
// both errors will be ENOTDIR, so it's okay to
|
| 232 |
|
|
// use the error from unlink.
|
| 233 |
|
|
if e1 != syscall.ENOTDIR {
|
| 234 |
|
|
e = e1
|
| 235 |
|
|
}
|
| 236 |
|
|
return &PathError{"remove", name, e}
|
| 237 |
|
|
}
|
| 238 |
|
|
|
| 239 |
|
|
// basename removes trailing slashes and the leading directory name from path name
|
| 240 |
|
|
func basename(name string) string {
|
| 241 |
|
|
i := len(name) - 1
|
| 242 |
|
|
// Remove trailing slashes
|
| 243 |
|
|
for ; i > 0 && name[i] == '/'; i-- {
|
| 244 |
|
|
name = name[:i]
|
| 245 |
|
|
}
|
| 246 |
|
|
// Remove leading directory name
|
| 247 |
|
|
for i--; i >= 0; i-- {
|
| 248 |
|
|
if name[i] == '/' {
|
| 249 |
|
|
name = name[i+1:]
|
| 250 |
|
|
break
|
| 251 |
|
|
}
|
| 252 |
|
|
}
|
| 253 |
|
|
|
| 254 |
|
|
return name
|
| 255 |
|
|
}
|
| 256 |
|
|
|
| 257 |
|
|
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
|
| 258 |
|
|
// It returns the files and an error, if any.
|
| 259 |
|
|
func Pipe() (r *File, w *File, err error) {
|
| 260 |
|
|
var p [2]int
|
| 261 |
|
|
|
| 262 |
|
|
// See ../syscall/exec.go for description of lock.
|
| 263 |
|
|
syscall.ForkLock.RLock()
|
| 264 |
|
|
e := syscall.Pipe(p[0:])
|
| 265 |
|
|
if e != nil {
|
| 266 |
|
|
syscall.ForkLock.RUnlock()
|
| 267 |
|
|
return nil, nil, NewSyscallError("pipe", e)
|
| 268 |
|
|
}
|
| 269 |
|
|
syscall.CloseOnExec(p[0])
|
| 270 |
|
|
syscall.CloseOnExec(p[1])
|
| 271 |
|
|
syscall.ForkLock.RUnlock()
|
| 272 |
|
|
|
| 273 |
|
|
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
|
| 274 |
|
|
}
|
| 275 |
|
|
|
| 276 |
|
|
// TempDir returns the default directory to use for temporary files.
|
| 277 |
|
|
func TempDir() string {
|
| 278 |
|
|
dir := Getenv("TMPDIR")
|
| 279 |
|
|
if dir == "" {
|
| 280 |
|
|
dir = "/tmp"
|
| 281 |
|
|
}
|
| 282 |
|
|
return dir
|
| 283 |
|
|
}
|