github.com/dara-project/godist@v0.0.0-20200823115410-e0c80c8f0c78/src/os/file_unix.go (about) 1 // 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 dragonfly freebsd linux nacl netbsd openbsd solaris 6 7 package os 8 9 import ( 10 "dara" 11 "internal/poll" 12 "runtime" 13 "syscall" 14 ) 15 16 // fixLongPath is a noop on non-Windows platforms. 17 func fixLongPath(path string) string { 18 return path 19 } 20 21 func rename(oldname, newname string) error { 22 fi, err := Lstat(newname) 23 if err == nil && fi.IsDir() { 24 // There are two independent errors this function can return: 25 // one for a bad oldname, and one for a bad newname. 26 // At this point we've determined the newname is bad. 27 // But just in case oldname is also bad, prioritize returning 28 // the oldname error because that's what we did historically. 29 if _, err := Lstat(oldname); err != nil { 30 if pe, ok := err.(*PathError); ok { 31 err = pe.Err 32 } 33 return &LinkError{"rename", oldname, newname, err} 34 } 35 return &LinkError{"rename", oldname, newname, syscall.EEXIST} 36 } 37 // DARA Instrumentation 38 if runtime.Is_dara_profiling_on() { 39 runtime.Dara_Debug_Print(func() { 40 print("[RENAME] : ") 41 print(oldname) 42 print(" ") 43 println(newname) 44 }) 45 argInfo1 := dara.GeneralType{Type: dara.STRING} 46 copy(argInfo1.String[:], oldname) 47 argInfo2 := dara.GeneralType{Type: dara.STRING} 48 copy(argInfo2.String[:], newname) 49 retInfo := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 50 syscallInfo := dara.GeneralSyscall{dara.DSYS_RENAME, 2, 1, [10]dara.GeneralType{argInfo1, argInfo2}, [10]dara.GeneralType{retInfo}} 51 runtime.Report_Syscall_To_Scheduler(dara.DSYS_RENAME, syscallInfo) 52 } 53 err = syscall.Rename(oldname, newname) 54 if err != nil { 55 return &LinkError{"rename", oldname, newname, err} 56 } 57 return nil 58 } 59 60 // file is the real representation of *File. 61 // The extra level of indirection ensures that no clients of os 62 // can overwrite this data, which could cause the finalizer 63 // to close the wrong file descriptor. 64 type file struct { 65 pfd poll.FD 66 name string 67 dirinfo *dirInfo // nil unless directory being read 68 nonblock bool // whether we set nonblocking mode 69 stdoutOrErr bool // whether this is stdout or stderr 70 } 71 72 // Fd returns the integer Unix file descriptor referencing the open file. 73 // The file descriptor is valid only until f.Close is called or f is garbage collected. 74 // On Unix systems this will cause the SetDeadline methods to stop working. 75 func (f *File) Fd() uintptr { 76 if f == nil { 77 return ^(uintptr(0)) 78 } 79 80 // If we put the file descriptor into nonblocking mode, 81 // then set it to blocking mode before we return it, 82 // because historically we have always returned a descriptor 83 // opened in blocking mode. The File will continue to work, 84 // but any blocking operation will tie up a thread. 85 if f.nonblock { 86 f.pfd.SetBlocking() 87 } 88 89 return uintptr(f.pfd.Sysfd) 90 } 91 92 // NewFile returns a new File with the given file descriptor and 93 // name. The returned value will be nil if fd is not a valid file 94 // descriptor. 95 func NewFile(fd uintptr, name string) *File { 96 return newFile(fd, name, kindNewFile) 97 } 98 99 // newFileKind describes the kind of file to newFile. 100 type newFileKind int 101 102 const ( 103 kindNewFile newFileKind = iota 104 kindOpenFile 105 kindPipe 106 ) 107 108 // newFile is like NewFile, but if called from OpenFile or Pipe 109 // (as passed in the kind parameter) it tries to add the file to 110 // the runtime poller. 111 func newFile(fd uintptr, name string, kind newFileKind) *File { 112 fdi := int(fd) 113 if fdi < 0 { 114 return nil 115 } 116 f := &File{&file{ 117 pfd: poll.FD{ 118 Sysfd: fdi, 119 IsStream: true, 120 ZeroReadIsEOF: true, 121 }, 122 name: name, 123 stdoutOrErr: fdi == 1 || fdi == 2, 124 }} 125 126 // Don't try to use kqueue with regular files on FreeBSD. 127 // It crashes the system unpredictably while running all.bash. 128 // Issue 19093. 129 if runtime.GOOS == "freebsd" && kind == kindOpenFile { 130 kind = kindNewFile 131 } 132 133 pollable := kind == kindOpenFile || kind == kindPipe 134 if err := f.pfd.Init("file", pollable); err != nil { 135 // An error here indicates a failure to register 136 // with the netpoll system. That can happen for 137 // a file descriptor that is not supported by 138 // epoll/kqueue; for example, disk files on 139 // GNU/Linux systems. We assume that any real error 140 // will show up in later I/O. 141 } else if pollable { 142 // We successfully registered with netpoll, so put 143 // the file into nonblocking mode. 144 if err := syscall.SetNonblock(fdi, true); err == nil { 145 f.nonblock = true 146 } 147 } 148 149 runtime.SetFinalizer(f.file, (*file).close) 150 return f 151 } 152 153 // Auxiliary information if the File describes a directory 154 type dirInfo struct { 155 buf []byte // buffer for directory I/O 156 nbuf int // length of buf; return value from Getdirentries 157 bufp int // location of next record in buf. 158 } 159 160 // epipecheck raises SIGPIPE if we get an EPIPE error on standard 161 // output or standard error. See the SIGPIPE docs in os/signal, and 162 // issue 11845. 163 func epipecheck(file *File, e error) { 164 if e == syscall.EPIPE && file.stdoutOrErr { 165 sigpipe() 166 } 167 } 168 169 // DevNull is the name of the operating system's ``null device.'' 170 // On Unix-like systems, it is "/dev/null"; on Windows, "NUL". 171 const DevNull = "/dev/null" 172 173 // openFileNolog is the Unix implementation of OpenFile. 174 func openFileNolog(name string, flag int, perm FileMode) (*File, error) { 175 chmod := false 176 if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 { 177 if _, err := Stat(name); IsNotExist(err) { 178 chmod = true 179 } 180 } 181 182 // DARA Instrumentation 183 if runtime.Is_dara_profiling_on() { 184 runtime.Dara_Debug_Print(func() { 185 print("[OPEN] : ") 186 print(name + " ") 187 print(flag) 188 print(" ") 189 println(perm) 190 }) 191 argInfo1 := dara.GeneralType{Type: dara.STRING} 192 copy(argInfo1.String[:], name) 193 argInfo2 := dara.GeneralType{Type: dara.INTEGER, Integer: flag} 194 argInfo3 := dara.GeneralType{Type: dara.INTEGER, Integer: int(perm)} 195 retInfo1 := dara.GeneralType{Type: dara.POINTER, Unsupported: dara.UNSUPPORTEDVAL} 196 retInfo2 := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 197 syscallInfo := dara.GeneralSyscall{dara.DSYS_OPEN, 3, 2, [10]dara.GeneralType{argInfo1, argInfo2, argInfo3}, [10]dara.GeneralType{retInfo1, retInfo2}} 198 runtime.Report_Syscall_To_Scheduler(dara.DSYS_OPEN, syscallInfo) 199 } 200 var r int 201 for { 202 var e error 203 r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) 204 if e == nil { 205 break 206 } 207 208 // On OS X, sigaction(2) doesn't guarantee that SA_RESTART will cause 209 // open(2) to be restarted for regular files. This is easy to reproduce on 210 // fuse file systems (see http://golang.org/issue/11180). 211 if runtime.GOOS == "darwin" && e == syscall.EINTR { 212 continue 213 } 214 215 return nil, &PathError{"open", name, e} 216 } 217 218 // open(2) itself won't handle the sticky bit on *BSD and Solaris 219 if chmod { 220 Chmod(name, perm) 221 } 222 223 // There's a race here with fork/exec, which we are 224 // content to live with. See ../syscall/exec_unix.go. 225 if !supportsCloseOnExec { 226 syscall.CloseOnExec(r) 227 } 228 229 return newFile(uintptr(r), name, kindOpenFile), nil 230 } 231 232 // Close closes the File, rendering it unusable for I/O. 233 // It returns an error, if any. 234 func (f *File) Close() error { 235 if f == nil { 236 return ErrInvalid 237 } 238 return f.file.close() 239 } 240 241 func (file *file) close() error { 242 if file == nil { 243 return syscall.EINVAL 244 } 245 // DARA Instrumentation 246 if runtime.Is_dara_profiling_on() { 247 runtime.Dara_Debug_Print(func() { 248 print("[CLOSE] : ") 249 println(file.name) 250 }) 251 argInfo := dara.GeneralType{Type: dara.FILE} 252 copy(argInfo.String[:], file.name) 253 retInfo := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 254 syscallInfo := dara.GeneralSyscall{dara.DSYS_CLOSE, 1, 1, [10]dara.GeneralType{argInfo}, [10]dara.GeneralType{retInfo}} 255 runtime.Report_Syscall_To_Scheduler(dara.DSYS_CLOSE, syscallInfo) 256 } 257 var err error 258 if e := file.pfd.Close(); e != nil { 259 if e == poll.ErrFileClosing { 260 e = ErrClosed 261 } 262 err = &PathError{"close", file.name, e} 263 } 264 265 // no need for a finalizer anymore 266 runtime.SetFinalizer(file, nil) 267 return err 268 } 269 270 // read reads up to len(b) bytes from the File. 271 // It returns the number of bytes read and an error, if any. 272 func (f *File) read(b []byte) (n int, err error) { 273 n, err = f.pfd.Read(b) 274 runtime.KeepAlive(f) 275 // DARA Instrumentation 276 if runtime.Is_dara_profiling_on() { 277 runtime.Dara_Debug_Print(func() { 278 print("[READ] : ") 279 println(f.file.name) 280 }) 281 argInfo1 := dara.GeneralType{Type: dara.FILE} 282 copy(argInfo1.String[:], f.name) 283 argInfo2 := dara.GeneralType{Type: dara.ARRAY, Integer: len(b)} 284 retInfo1 := dara.GeneralType{Type: dara.INTEGER, Integer: n} 285 retInfo2 := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 286 syscallInfo := dara.GeneralSyscall{dara.DSYS_READ, 2, 2, [10]dara.GeneralType{argInfo1, argInfo2}, [10]dara.GeneralType{retInfo1, retInfo2}} 287 runtime.Report_Syscall_To_Scheduler(dara.DSYS_READ, syscallInfo) 288 } 289 return n, err 290 } 291 292 // pread reads len(b) bytes from the File starting at byte offset off. 293 // It returns the number of bytes read and the error, if any. 294 // EOF is signaled by a zero count with err set to nil. 295 func (f *File) pread(b []byte, off int64) (n int, err error) { 296 n, err = f.pfd.Pread(b, off) 297 runtime.KeepAlive(f) 298 // DARA Instrumentation 299 if runtime.Is_dara_profiling_on() { 300 runtime.Dara_Debug_Print(func() { 301 print("[PREAD] : ") 302 print(f.file.name) 303 print(" ") 304 println(off) 305 }) 306 argInfo1 := dara.GeneralType{Type: dara.FILE} 307 copy(argInfo1.String[:], f.name) 308 argInfo2 := dara.GeneralType{Type: dara.ARRAY, Integer: len(b)} 309 argInfo3 := dara.GeneralType{Type: dara.INTEGER64, Integer64: off} 310 retInfo1 := dara.GeneralType{Type: dara.INTEGER, Integer: n} 311 retInfo2 := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 312 syscallInfo := dara.GeneralSyscall{dara.DSYS_PREAD64, 3, 2, [10]dara.GeneralType{argInfo1, argInfo2, argInfo3}, [10]dara.GeneralType{retInfo1, retInfo2}} 313 runtime.Report_Syscall_To_Scheduler(dara.DSYS_PREAD64, syscallInfo) 314 } 315 return n, err 316 } 317 318 // write writes len(b) bytes to the File. 319 // It returns the number of bytes written and an error, if any. 320 func (f *File) write(b []byte) (n int, err error) { 321 n, err = f.pfd.Write(b) 322 runtime.KeepAlive(f) 323 // DARA Instrumentation 324 if runtime.Is_dara_profiling_on() { 325 runtime.Dara_Debug_Print(func() { 326 print("[WRITE] : ") 327 print(f.file.name) 328 print(" ") 329 println(string(b[:len(b)])) 330 }) 331 argInfo1 := dara.GeneralType{Type: dara.FILE} 332 copy(argInfo1.String[:], f.name) 333 argInfo2 := dara.GeneralType{Type: dara.ARRAY, Integer: len(b)} 334 retInfo1 := dara.GeneralType{Type: dara.INTEGER, Integer: n} 335 retInfo2 := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 336 syscallInfo := dara.GeneralSyscall{dara.DSYS_WRITE, 2, 2, [10]dara.GeneralType{argInfo1, argInfo2}, [10]dara.GeneralType{retInfo1, retInfo2}} 337 runtime.Report_Syscall_To_Scheduler(dara.DSYS_WRITE, syscallInfo) 338 } 339 return n, err 340 } 341 342 // pwrite writes len(b) bytes to the File starting at byte offset off. 343 // It returns the number of bytes written and an error, if any. 344 func (f *File) pwrite(b []byte, off int64) (n int, err error) { 345 // DARA Instrumentation 346 if runtime.Is_dara_profiling_on() { 347 runtime.Dara_Debug_Print(func() { 348 print("[PWRITE] : ") 349 print(f.file.name) 350 print(" ") 351 print(string(b[:len(b)])) 352 print(" ") 353 println(off) 354 }) 355 argInfo1 := dara.GeneralType{Type: dara.FILE} 356 copy(argInfo1.String[:], f.name) 357 argInfo2 := dara.GeneralType{Type: dara.ARRAY, Integer: len(b)} 358 argInfo3 := dara.GeneralType{Type: dara.INTEGER64, Integer64: off} 359 retInfo1 := dara.GeneralType{Type: dara.INTEGER, Integer: n} 360 retInfo2 := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 361 syscallInfo := dara.GeneralSyscall{dara.DSYS_PWRITE64, 3, 2, [10]dara.GeneralType{argInfo1, argInfo2, argInfo3}, [10]dara.GeneralType{retInfo1, retInfo2}} 362 runtime.Report_Syscall_To_Scheduler(dara.DSYS_PWRITE64, syscallInfo) 363 } 364 n, err = f.pfd.Pwrite(b, off) 365 runtime.KeepAlive(f) 366 return n, err 367 } 368 369 // seek sets the offset for the next Read or Write on file to offset, interpreted 370 // according to whence: 0 means relative to the origin of the file, 1 means 371 // relative to the current offset, and 2 means relative to the end. 372 // It returns the new offset and an error, if any. 373 func (f *File) seek(offset int64, whence int) (ret int64, err error) { 374 ret, err = f.pfd.Seek(offset, whence) 375 runtime.KeepAlive(f) 376 // DARA Instrumentation 377 if runtime.Is_dara_profiling_on() { 378 runtime.Dara_Debug_Print(func() { 379 print("[SEEK] : ") 380 print(f.file.name) 381 print(" ") 382 print(offset) 383 print(" ") 384 println(whence) 385 }) 386 argInfo1 := dara.GeneralType{Type: dara.FILE} 387 copy(argInfo1.String[:], f.name) 388 argInfo2 := dara.GeneralType{Type: dara.INTEGER64, Integer64: offset} 389 argInfo3 := dara.GeneralType{Type: dara.INTEGER, Integer: whence} 390 retInfo1 := dara.GeneralType{Type: dara.INTEGER64, Integer64: ret} 391 retInfo2 := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 392 syscallInfo := dara.GeneralSyscall{dara.DSYS_LSEEK, 3, 2, [10]dara.GeneralType{argInfo1, argInfo2, argInfo3}, [10]dara.GeneralType{retInfo1, retInfo2}} 393 runtime.Report_Syscall_To_Scheduler(dara.DSYS_LSEEK, syscallInfo) 394 } 395 return ret, err 396 } 397 398 // Truncate changes the size of the named file. 399 // If the file is a symbolic link, it changes the size of the link's target. 400 // If there is an error, it will be of type *PathError. 401 func Truncate(name string, size int64) error { 402 // DARA Instrumentation 403 if runtime.Is_dara_profiling_on() { 404 runtime.Dara_Debug_Print(func() { 405 print("[TRUNCATE] : ") 406 print(name) 407 print(" ") 408 println(size) 409 }) 410 argInfo1 := dara.GeneralType{Type: dara.STRING} 411 copy(argInfo1.String[:], name) 412 argInfo2 := dara.GeneralType{Type: dara.INTEGER64, Integer64: size} 413 retInfo := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 414 syscallInfo := dara.GeneralSyscall{dara.DSYS_TRUNCATE, 2, 1, [10]dara.GeneralType{argInfo1, argInfo2}, [10]dara.GeneralType{retInfo}} 415 runtime.Report_Syscall_To_Scheduler(dara.DSYS_TRUNCATE, syscallInfo) 416 } 417 if e := syscall.Truncate(name, size); e != nil { 418 return &PathError{"truncate", name, e} 419 } 420 return nil 421 } 422 423 // Remove removes the named file or directory. 424 // If there is an error, it will be of type *PathError. 425 func Remove(name string) error { 426 // System call interface forces us to know 427 // whether name is a file or directory. 428 // Try both: it is cheaper on average than 429 // doing a Stat plus the right one 430 e := syscall.Unlink(name) 431 if e == nil { 432 return nil 433 } 434 e1 := syscall.Rmdir(name) 435 if e1 == nil { 436 return nil 437 } 438 439 // Both failed: figure out which error to return. 440 // OS X and Linux differ on whether unlink(dir) 441 // returns EISDIR, so can't use that. However, 442 // both agree that rmdir(file) returns ENOTDIR, 443 // so we can use that to decide which error is real. 444 // Rmdir might also return ENOTDIR if given a bad 445 // file path, like /etc/passwd/foo, but in that case, 446 // both errors will be ENOTDIR, so it's okay to 447 // use the error from unlink. 448 if e1 != syscall.ENOTDIR { 449 e = e1 450 } 451 return &PathError{"remove", name, e} 452 } 453 454 func tempDir() string { 455 dir := Getenv("TMPDIR") 456 if dir == "" { 457 if runtime.GOOS == "android" { 458 dir = "/data/local/tmp" 459 } else { 460 dir = "/tmp" 461 } 462 } 463 return dir 464 } 465 466 // Link creates newname as a hard link to the oldname file. 467 // If there is an error, it will be of type *LinkError. 468 func Link(oldname, newname string) error { 469 e := syscall.Link(oldname, newname) 470 // DARA Instrumentation 471 if runtime.Is_dara_profiling_on() { 472 runtime.Dara_Debug_Print(func() { 473 print("[LINK] : ") 474 print(oldname) 475 print(" ") 476 println(newname) 477 }) 478 argInfo1 := dara.GeneralType{Type: dara.STRING} 479 copy(argInfo1.String[:], oldname) 480 argInfo2 := dara.GeneralType{Type: dara.STRING} 481 copy(argInfo2.String[:], newname) 482 retInfo := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 483 syscallInfo := dara.GeneralSyscall{dara.DSYS_LINK, 2, 1, [10]dara.GeneralType{argInfo1, argInfo2}, [10]dara.GeneralType{retInfo}} 484 runtime.Report_Syscall_To_Scheduler(dara.DSYS_LINK, syscallInfo) 485 } 486 if e != nil { 487 return &LinkError{"link", oldname, newname, e} 488 } 489 return nil 490 } 491 492 // Symlink creates newname as a symbolic link to oldname. 493 // If there is an error, it will be of type *LinkError. 494 func Symlink(oldname, newname string) error { 495 e := syscall.Symlink(oldname, newname) 496 // DARA Instrumentation 497 if runtime.Is_dara_profiling_on() { 498 runtime.Dara_Debug_Print(func() { 499 print("[LINK] : ") 500 print(oldname) 501 print(" ") 502 println(newname) 503 }) 504 argInfo1 := dara.GeneralType{Type: dara.STRING} 505 copy(argInfo1.String[:], oldname) 506 argInfo2 := dara.GeneralType{Type: dara.STRING} 507 copy(argInfo2.String[:], newname) 508 retInfo := dara.GeneralType{Type: dara.ERROR, Unsupported: dara.UNSUPPORTEDVAL} 509 syscallInfo := dara.GeneralSyscall{dara.DSYS_SYMLINK, 2, 1, [10]dara.GeneralType{argInfo1, argInfo2}, [10]dara.GeneralType{retInfo}} 510 runtime.Report_Syscall_To_Scheduler(dara.DSYS_SYMLINK, syscallInfo) 511 } 512 if e != nil { 513 return &LinkError{"symlink", oldname, newname, e} 514 } 515 return nil 516 }