github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/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 //go:build unix || (js && wasm) || wasip1 6 7 package os 8 9 import ( 10 "internal/poll" 11 "internal/syscall/unix" 12 "io/fs" 13 "runtime" 14 "syscall" 15 ) 16 17 const _UTIME_OMIT = unix.UTIME_OMIT 18 19 // fixLongPath is a noop on non-Windows platforms. 20 func fixLongPath(path string) string { 21 return path 22 } 23 24 func rename(oldname, newname string) error { 25 fi, err := Lstat(newname) 26 if err == nil && fi.IsDir() { 27 // There are two independent errors this function can return: 28 // one for a bad oldname, and one for a bad newname. 29 // At this point we've determined the newname is bad. 30 // But just in case oldname is also bad, prioritize returning 31 // the oldname error because that's what we did historically. 32 // However, if the old name and new name are not the same, yet 33 // they refer to the same file, it implies a case-only 34 // rename on a case-insensitive filesystem, which is ok. 35 if ofi, err := Lstat(oldname); err != nil { 36 if pe, ok := err.(*PathError); ok { 37 err = pe.Err 38 } 39 return &LinkError{"rename", oldname, newname, err} 40 } else if newname == oldname || !SameFile(fi, ofi) { 41 return &LinkError{"rename", oldname, newname, syscall.EEXIST} 42 } 43 } 44 err = ignoringEINTR(func() error { 45 return syscall.Rename(oldname, newname) 46 }) 47 if err != nil { 48 return &LinkError{"rename", oldname, newname, err} 49 } 50 return nil 51 } 52 53 // file is the real representation of *File. 54 // The extra level of indirection ensures that no clients of os 55 // can overwrite this data, which could cause the finalizer 56 // to close the wrong file descriptor. 57 type file struct { 58 pfd poll.FD 59 name string 60 dirinfo *dirInfo // nil unless directory being read 61 nonblock bool // whether we set nonblocking mode 62 stdoutOrErr bool // whether this is stdout or stderr 63 appendMode bool // whether file is opened for appending 64 } 65 66 // Fd returns the integer Unix file descriptor referencing the open file. 67 // If f is closed, the file descriptor becomes invalid. 68 // If f is garbage collected, a finalizer may close the file descriptor, 69 // making it invalid; see runtime.SetFinalizer for more information on when 70 // a finalizer might be run. On Unix systems this will cause the SetDeadline 71 // methods to stop working. 72 // Because file descriptors can be reused, the returned file descriptor may 73 // only be closed through the Close method of f, or by its finalizer during 74 // garbage collection. Otherwise, during garbage collection the finalizer 75 // may close an unrelated file descriptor with the same (reused) number. 76 // 77 // As an alternative, see the f.SyscallConn method. 78 func (f *File) Fd() uintptr { 79 if f == nil { 80 return ^(uintptr(0)) 81 } 82 83 // If we put the file descriptor into nonblocking mode, 84 // then set it to blocking mode before we return it, 85 // because historically we have always returned a descriptor 86 // opened in blocking mode. The File will continue to work, 87 // but any blocking operation will tie up a thread. 88 if f.nonblock { 89 f.pfd.SetBlocking() 90 } 91 92 return uintptr(f.pfd.Sysfd) 93 } 94 95 // NewFile returns a new File with the given file descriptor and 96 // name. The returned value will be nil if fd is not a valid file 97 // descriptor. On Unix systems, if the file descriptor is in 98 // non-blocking mode, NewFile will attempt to return a pollable File 99 // (one for which the SetDeadline methods work). 100 // 101 // After passing it to NewFile, fd may become invalid under the same 102 // conditions described in the comments of the Fd method, and the same 103 // constraints apply. 104 func NewFile(fd uintptr, name string) *File { 105 kind := kindNewFile 106 if nb, err := unix.IsNonblock(int(fd)); err == nil && nb { 107 kind = kindNonBlock 108 } 109 f := newFile(fd, name, kind) 110 if flags, err := unix.Fcntl(int(fd), syscall.F_GETFL, 0); err == nil { 111 f.appendMode = flags&syscall.O_APPEND != 0 112 } 113 return f 114 } 115 116 // newFileKind describes the kind of file to newFile. 117 type newFileKind int 118 119 const ( 120 // kindNewFile means that the descriptor was passed to us via NewFile. 121 kindNewFile newFileKind = iota 122 // kindOpenFile means that the descriptor was opened using 123 // Open, Create, or OpenFile (without O_NONBLOCK). 124 kindOpenFile 125 // kindPipe means that the descriptor was opened using Pipe. 126 kindPipe 127 // kindNonBlock means that the descriptor is already in 128 // non-blocking mode. 129 kindNonBlock 130 // kindNoPoll means that we should not put the descriptor into 131 // non-blocking mode, because we know it is not a pipe or FIFO. 132 // Used by openFdAt for directories. 133 kindNoPoll 134 ) 135 136 // newFile is like NewFile, but if called from OpenFile or Pipe 137 // (as passed in the kind parameter) it tries to add the file to 138 // the runtime poller. 139 func newFile(fd uintptr, name string, kind newFileKind) *File { 140 fdi := int(fd) 141 if fdi < 0 { 142 return nil 143 } 144 f := &File{&file{ 145 pfd: poll.FD{ 146 Sysfd: fdi, 147 IsStream: true, 148 ZeroReadIsEOF: true, 149 }, 150 name: name, 151 stdoutOrErr: fdi == 1 || fdi == 2, 152 }} 153 154 pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock 155 156 // If the caller passed a non-blocking filedes (kindNonBlock), 157 // we assume they know what they are doing so we allow it to be 158 // used with kqueue. 159 if kind == kindOpenFile { 160 switch runtime.GOOS { 161 case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd": 162 var st syscall.Stat_t 163 err := ignoringEINTR(func() error { 164 return syscall.Fstat(fdi, &st) 165 }) 166 typ := st.Mode & syscall.S_IFMT 167 // Don't try to use kqueue with regular files on *BSDs. 168 // On FreeBSD a regular file is always 169 // reported as ready for writing. 170 // On Dragonfly, NetBSD and OpenBSD the fd is signaled 171 // only once as ready (both read and write). 172 // Issue 19093. 173 // Also don't add directories to the netpoller. 174 if err == nil && (typ == syscall.S_IFREG || typ == syscall.S_IFDIR) { 175 pollable = false 176 } 177 178 // In addition to the behavior described above for regular files, 179 // on Darwin, kqueue does not work properly with fifos: 180 // closing the last writer does not cause a kqueue event 181 // for any readers. See issue #24164. 182 if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && typ == syscall.S_IFIFO { 183 pollable = false 184 } 185 } 186 } 187 188 clearNonBlock := false 189 if pollable { 190 if kind == kindNonBlock { 191 // The descriptor is already in non-blocking mode. 192 // We only set f.nonblock if we put the file into 193 // non-blocking mode. 194 } else if err := syscall.SetNonblock(fdi, true); err == nil { 195 f.nonblock = true 196 clearNonBlock = true 197 } else { 198 pollable = false 199 } 200 } 201 202 // An error here indicates a failure to register 203 // with the netpoll system. That can happen for 204 // a file descriptor that is not supported by 205 // epoll/kqueue; for example, disk files on 206 // Linux systems. We assume that any real error 207 // will show up in later I/O. 208 // We do restore the blocking behavior if it was set by us. 209 if pollErr := f.pfd.Init("file", pollable); pollErr != nil && clearNonBlock { 210 if err := syscall.SetNonblock(fdi, false); err == nil { 211 f.nonblock = false 212 } 213 } 214 215 runtime.SetFinalizer(f.file, (*file).close) 216 return f 217 } 218 219 func sigpipe() // implemented in package runtime 220 221 // epipecheck raises SIGPIPE if we get an EPIPE error on standard 222 // output or standard error. See the SIGPIPE docs in os/signal, and 223 // issue 11845. 224 func epipecheck(file *File, e error) { 225 if e == syscall.EPIPE && file.stdoutOrErr { 226 sigpipe() 227 } 228 } 229 230 // DevNull is the name of the operating system's “null device.” 231 // On Unix-like systems, it is "/dev/null"; on Windows, "NUL". 232 const DevNull = "/dev/null" 233 234 // openFileNolog is the Unix implementation of OpenFile. 235 // Changes here should be reflected in openFdAt, if relevant. 236 func openFileNolog(name string, flag int, perm FileMode) (*File, error) { 237 setSticky := false 238 if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 { 239 if _, err := Stat(name); IsNotExist(err) { 240 setSticky = true 241 } 242 } 243 244 var r int 245 var s poll.SysFile 246 for { 247 var e error 248 r, s, e = open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) 249 if e == nil { 250 break 251 } 252 253 // We have to check EINTR here, per issues 11180 and 39237. 254 if e == syscall.EINTR { 255 continue 256 } 257 258 return nil, &PathError{Op: "open", Path: name, Err: e} 259 } 260 261 // open(2) itself won't handle the sticky bit on *BSD and Solaris 262 if setSticky { 263 setStickyBit(name) 264 } 265 266 // There's a race here with fork/exec, which we are 267 // content to live with. See ../syscall/exec_unix.go. 268 if !supportsCloseOnExec { 269 syscall.CloseOnExec(r) 270 } 271 272 kind := kindOpenFile 273 if unix.HasNonblockFlag(flag) { 274 kind = kindNonBlock 275 } 276 277 f := newFile(uintptr(r), name, kind) 278 f.pfd.SysFile = s 279 return f, nil 280 } 281 282 func (file *file) close() error { 283 if file == nil { 284 return syscall.EINVAL 285 } 286 if file.dirinfo != nil { 287 file.dirinfo.close() 288 file.dirinfo = nil 289 } 290 var err error 291 if e := file.pfd.Close(); e != nil { 292 if e == poll.ErrFileClosing { 293 e = ErrClosed 294 } 295 err = &PathError{Op: "close", Path: file.name, Err: e} 296 } 297 298 // no need for a finalizer anymore 299 runtime.SetFinalizer(file, nil) 300 return err 301 } 302 303 // seek sets the offset for the next Read or Write on file to offset, interpreted 304 // according to whence: 0 means relative to the origin of the file, 1 means 305 // relative to the current offset, and 2 means relative to the end. 306 // It returns the new offset and an error, if any. 307 func (f *File) seek(offset int64, whence int) (ret int64, err error) { 308 if f.dirinfo != nil { 309 // Free cached dirinfo, so we allocate a new one if we 310 // access this file as a directory again. See #35767 and #37161. 311 f.dirinfo.close() 312 f.dirinfo = nil 313 } 314 ret, err = f.pfd.Seek(offset, whence) 315 runtime.KeepAlive(f) 316 return ret, err 317 } 318 319 // Truncate changes the size of the named file. 320 // If the file is a symbolic link, it changes the size of the link's target. 321 // If there is an error, it will be of type *PathError. 322 func Truncate(name string, size int64) error { 323 e := ignoringEINTR(func() error { 324 return syscall.Truncate(name, size) 325 }) 326 if e != nil { 327 return &PathError{Op: "truncate", Path: name, Err: e} 328 } 329 return nil 330 } 331 332 // Remove removes the named file or (empty) directory. 333 // If there is an error, it will be of type *PathError. 334 func Remove(name string) error { 335 // System call interface forces us to know 336 // whether name is a file or directory. 337 // Try both: it is cheaper on average than 338 // doing a Stat plus the right one. 339 e := ignoringEINTR(func() error { 340 return syscall.Unlink(name) 341 }) 342 if e == nil { 343 return nil 344 } 345 e1 := ignoringEINTR(func() error { 346 return syscall.Rmdir(name) 347 }) 348 if e1 == nil { 349 return nil 350 } 351 352 // Both failed: figure out which error to return. 353 // OS X and Linux differ on whether unlink(dir) 354 // returns EISDIR, so can't use that. However, 355 // both agree that rmdir(file) returns ENOTDIR, 356 // so we can use that to decide which error is real. 357 // Rmdir might also return ENOTDIR if given a bad 358 // file path, like /etc/passwd/foo, but in that case, 359 // both errors will be ENOTDIR, so it's okay to 360 // use the error from unlink. 361 if e1 != syscall.ENOTDIR { 362 e = e1 363 } 364 return &PathError{Op: "remove", Path: name, Err: e} 365 } 366 367 func tempDir() string { 368 dir := Getenv("TMPDIR") 369 if dir == "" { 370 if runtime.GOOS == "android" { 371 dir = "/data/local/tmp" 372 } else { 373 dir = "/tmp" 374 } 375 } 376 return dir 377 } 378 379 // Link creates newname as a hard link to the oldname file. 380 // If there is an error, it will be of type *LinkError. 381 func Link(oldname, newname string) error { 382 e := ignoringEINTR(func() error { 383 return syscall.Link(oldname, newname) 384 }) 385 if e != nil { 386 return &LinkError{"link", oldname, newname, e} 387 } 388 return nil 389 } 390 391 // Symlink creates newname as a symbolic link to oldname. 392 // On Windows, a symlink to a non-existent oldname creates a file symlink; 393 // if oldname is later created as a directory the symlink will not work. 394 // If there is an error, it will be of type *LinkError. 395 func Symlink(oldname, newname string) error { 396 e := ignoringEINTR(func() error { 397 return syscall.Symlink(oldname, newname) 398 }) 399 if e != nil { 400 return &LinkError{"symlink", oldname, newname, e} 401 } 402 return nil 403 } 404 405 // Readlink returns the destination of the named symbolic link. 406 // If there is an error, it will be of type *PathError. 407 func Readlink(name string) (string, error) { 408 for len := 128; ; len *= 2 { 409 b := make([]byte, len) 410 var ( 411 n int 412 e error 413 ) 414 for { 415 n, e = fixCount(syscall.Readlink(name, b)) 416 if e != syscall.EINTR { 417 break 418 } 419 } 420 // buffer too small 421 if (runtime.GOOS == "aix" || runtime.GOOS == "wasip1") && e == syscall.ERANGE { 422 continue 423 } 424 if e != nil { 425 return "", &PathError{Op: "readlink", Path: name, Err: e} 426 } 427 if n < len { 428 return string(b[0:n]), nil 429 } 430 } 431 } 432 433 type unixDirent struct { 434 parent string 435 name string 436 typ FileMode 437 info FileInfo 438 } 439 440 func (d *unixDirent) Name() string { return d.name } 441 func (d *unixDirent) IsDir() bool { return d.typ.IsDir() } 442 func (d *unixDirent) Type() FileMode { return d.typ } 443 444 func (d *unixDirent) Info() (FileInfo, error) { 445 if d.info != nil { 446 return d.info, nil 447 } 448 return lstat(d.parent + "/" + d.name) 449 } 450 451 func (d *unixDirent) String() string { 452 return fs.FormatDirEntry(d) 453 } 454 455 func newUnixDirent(parent, name string, typ FileMode) (DirEntry, error) { 456 ude := &unixDirent{ 457 parent: parent, 458 name: name, 459 typ: typ, 460 } 461 if typ != ^FileMode(0) && !testingForceReadDirLstat { 462 return ude, nil 463 } 464 465 info, err := lstat(parent + "/" + name) 466 if err != nil { 467 return nil, err 468 } 469 470 ude.typ = info.Mode().Type() 471 ude.info = info 472 return ude, nil 473 }