// 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.//go:build unix || (js && wasm) || wasip1package osimport (_// for go:linkname)const _UTIME_OMIT = unix.UTIME_OMIT// fixLongPath is a noop on non-Windows platforms.func fixLongPath( string) string {return}func rename(, string) error { , := Lstat()if == nil && .IsDir() {// 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. // However, if the old name and new name are not the same, yet // they refer to the same file, it implies a case-only // rename on a case-insensitive filesystem, which is ok.if , := Lstat(); != nil {if , := .(*PathError); { = .Err }return &LinkError{"rename", , , } } elseif == || !SameFile(, ) {return &LinkError{"rename", , , syscall.EEXIST} } } = ignoringEINTR(func() error {returnsyscall.Rename(, ) })if != nil {return &LinkError{"rename", , , } }returnnil}// 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 cleanup// to close the wrong file descriptor.type file struct { pfd poll.FD name string dirinfo atomic.Pointer[dirInfo] // nil unless directory being read nonblock bool// whether we set nonblocking mode stdoutOrErr bool// whether this is stdout or stderr appendMode bool// whether file is opened for appending cleanup runtime.Cleanup// cleanup closes the file when no longer referenced}// fd is the Unix implementation of Fd.func ( *File) () uintptr {if == nil {return ^(uintptr(0)) }// 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 .nonblock { .pfd.SetBlocking() }returnuintptr(.pfd.Sysfd)}// newFileFromNewFile is called by [NewFile].func newFileFromNewFile( uintptr, string) *File { := int()if < 0 {returnnil } , := unix.Fcntl(, syscall.F_GETFL, 0)if != nil { = 0 } := newFile(, , kindNewFile, unix.HasNonblockFlag()) .appendMode = &syscall.O_APPEND != 0return}// net_newUnixFile is a hidden entry point called by net.conn.File.// This is used so that a nonblocking network connection will become// blocking if code calls the Fd method. We don't want that for direct// calls to NewFile: passing a nonblocking descriptor to NewFile should// remain nonblocking if you get it back using Fd. But for net.conn.File// the call to NewFile is hidden from the user. Historically in that case// the Fd method has returned a blocking descriptor, and we want to// retain that behavior because existing code expects it and depends on it.////go:linkname net_newUnixFile net.newUnixFilefunc net_newUnixFile( int, string) *File {if < 0 {panic("invalid FD") }returnnewFile(, , kindSock, true)}// newFileKind describes the kind of file to newFile.type newFileKind intconst (// kindNewFile means that the descriptor was passed to us via NewFile. kindNewFile newFileKind = iota// kindOpenFile means that the descriptor was opened using // Open, Create, or OpenFile. kindOpenFile// kindPipe means that the descriptor was opened using Pipe. kindPipe// kindSock means that the descriptor is a network file descriptor // that was created from net package and was opened using net_newUnixFile. kindSock// kindNoPoll means that we should not put the descriptor into // non-blocking mode, because we know it is not a pipe or FIFO. // Used by openDirAt and openDirNolog for directories. kindNoPoll)// 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( int, string, newFileKind, bool) *File { := &File{&file{pfd: poll.FD{Sysfd: ,IsStream: true,ZeroReadIsEOF: true, },name: ,stdoutOrErr: == 1 || == 2, }} := == kindOpenFile || == kindPipe || == kindSock || // Things like regular files and FIFOs in kqueue on *BSD/Darwin // may not work properly (or accurately according to its manual). // As a result, we should avoid adding those to the kqueue-based // netpoller. Check out #19093, #24164, and #66239 for more contexts. // // If the fd was passed to us via any path other than OpenFile, // we assume those callers know what they were doing, so we won't // perform this check and allow it to be added to the kqueue.if == kindOpenFile {switchruntime.GOOS {case"darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd":varsyscall.Stat_t := ignoringEINTR(func() error {returnsyscall.Fstat(, &) }) := .Mode & syscall.S_IFMT// Don't try to use kqueue with regular files on *BSDs. // On FreeBSD a regular file is always // reported as ready for writing. // On Dragonfly, NetBSD and OpenBSD the fd is signaled // only once as ready (both read and write). // Issue 19093. // Also don't add directories to the netpoller.if == nil && ( == syscall.S_IFREG || == syscall.S_IFDIR) { = false }// In addition to the behavior described above for regular files, // on Darwin, kqueue does not work properly with fifos: // closing the last writer does not cause a kqueue event // for any readers. See issue #24164.if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && == syscall.S_IFIFO { = false } } } := falseif {// The descriptor is already in non-blocking mode. // We only set f.nonblock if we put the file into // non-blocking mode.if {// See the comments on net_newUnixFile.if == kindSock { .nonblock = true// tell Fd to return blocking descriptor } } elseif := syscall.SetNonblock(, true); == nil { .nonblock = true = true } else { = false } }// 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 // Linux systems. We assume that any real error // will show up in later I/O. // We do restore the blocking behavior if it was set by us.if := .pfd.Init("file", ); != nil && {if := syscall.SetNonblock(, false); == nil { .nonblock = false } }// Close the file when the File is not live. .cleanup = runtime.AddCleanup(, func( *file) { .close() }, .file)return}func sigpipe() // implemented in package runtime// 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.func epipecheck( *File, error) {if == syscall.EPIPE && .stdoutOrErr {sigpipe() }}// DevNull is the name of the operating system's “null device.”// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".constDevNull = "/dev/null"// openFileNolog is the Unix implementation of OpenFile.// Changes here should be reflected in openDirAt and openDirNolog, if relevant.func openFileNolog( string, int, FileMode) (*File, error) { := falseif !supportsCreateWithStickyBit && &O_CREATE != 0 && &ModeSticky != 0 {if , := Stat(); IsNotExist() { = true } }var (intpoll.SysFileerror )// We have to check EINTR here, per issues 11180 and 39237.ignoringEINTR(func() error { , , = open(, |syscall.O_CLOEXEC, syscallMode())return })if != nil {returnnil, &PathError{Op: "open", Path: , Err: } }// open(2) itself won't handle the sticky bit on *BSD and Solarisif {setStickyBit() }// There's a race here with fork/exec, which we are // content to live with. See ../syscall/exec_unix.go.if !supportsCloseOnExec {syscall.CloseOnExec() } := newFile(, , kindOpenFile, unix.HasNonblockFlag()) .pfd.SysFile = return , nil}func openDirNolog( string) (*File, error) {var (intpoll.SysFileerror )ignoringEINTR(func() error { , , = open(, O_RDONLY|syscall.O_CLOEXEC|syscall.O_DIRECTORY, 0)return })if != nil {returnnil, &PathError{Op: "open", Path: , Err: } }if !supportsCloseOnExec {syscall.CloseOnExec() } := newFile(, , kindNoPoll, false) .pfd.SysFile = return , nil}func ( *file) () error {if == nil {returnsyscall.EINVAL }if := .dirinfo.Swap(nil); != nil { .close() }varerrorif := .pfd.Close(); != nil {if == poll.ErrFileClosing { = ErrClosed } = &PathError{Op: "close", Path: .name, Err: } }// There is no need for a cleanup at this point. File must be alive at the point // where cleanup.stop is called. .cleanup.Stop()return}// 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.func ( *File) ( int64, int) ( int64, error) {if := .dirinfo.Swap(nil); != nil {// Free cached dirinfo, so we allocate a new one if we // access this file as a directory again. See #35767 and #37161. .close() } , = .pfd.Seek(, )runtime.KeepAlive()return , }// Truncate changes the size of the named file.// If the file is a symbolic link, it changes the size of the link's target.// If there is an error, it will be of type [*PathError].func ( string, int64) error { := ignoringEINTR(func() error {returnsyscall.Truncate(, ) })if != nil {return &PathError{Op: "truncate", Path: , Err: } }returnnil}// Remove removes the named file or (empty) directory.// If there is an error, it will be of type [*PathError].func ( 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. := ignoringEINTR(func() error {returnsyscall.Unlink() })if == nil {returnnil } := ignoringEINTR(func() error {returnsyscall.Rmdir() })if == nil {returnnil }// Both failed: figure out which error to return. // OS X and Linux differ on whether unlink(dir) // returns EISDIR, so can't use that. However, // 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 != syscall.ENOTDIR { = }return &PathError{Op: "remove", Path: , Err: }}func tempDir() string { := Getenv("TMPDIR")if == "" {ifruntime.GOOS == "android" { = "/data/local/tmp" } else { = "/tmp" } }return}// Link creates newname as a hard link to the oldname file.// If there is an error, it will be of type *LinkError.func (, string) error { := ignoringEINTR(func() error {returnsyscall.Link(, ) })if != nil {return &LinkError{"link", , , } }returnnil}// Symlink creates newname as a symbolic link to oldname.// On Windows, a symlink to a non-existent oldname creates a file symlink;// if oldname is later created as a directory the symlink will not work.// If there is an error, it will be of type *LinkError.func (, string) error { := ignoringEINTR(func() error {returnsyscall.Symlink(, ) })if != nil {return &LinkError{"symlink", , , } }returnnil}func readlink( string) (string, error) {for := 128; ; *= 2 { := make([]byte, ) , := ignoringEINTR2(func() (int, error) {returnfixCount(syscall.Readlink(, )) })// buffer too smallif (runtime.GOOS == "aix" || runtime.GOOS == "wasip1") && == syscall.ERANGE {continue }if != nil {return"", &PathError{Op: "readlink", Path: , Err: } }if < {returnstring([0:]), nil } }}type unixDirent struct { parent string name string typ FileMode info FileInfo}func ( *unixDirent) () string { return .name }func ( *unixDirent) () bool { return .typ.IsDir() }func ( *unixDirent) () FileMode { return .typ }func ( *unixDirent) () (FileInfo, error) {if .info != nil {return .info, nil }returnlstat(.parent + "/" + .name)}func ( *unixDirent) () string {returnfs.FormatDirEntry()}func newUnixDirent(, string, FileMode) (DirEntry, error) { := &unixDirent{parent: ,name: ,typ: , }if != ^FileMode(0) {return , nil } , := lstat( + "/" + )if != nil {returnnil, } .typ = .Mode().Type() .info = return , nil}
The pages are generated with Goldsv0.7.7-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.