// 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)package osimport ()// 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 finalizer// to close the wrong file descriptor.type file struct { 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 appendMode bool// whether file is opened for appending}// Fd returns the integer Unix file descriptor referencing the open file.// If f is closed, the file descriptor becomes invalid.// If f is garbage collected, a finalizer may close the file descriptor,// making it invalid; see runtime.SetFinalizer for more information on when// a finalizer might be run. On Unix systems this will cause the SetDeadline// methods to stop working.// Because file descriptors can be reused, the returned file descriptor may// only be closed through the Close method of f, or by its finalizer during// garbage collection. Otherwise, during garbage collection the finalizer// may close an unrelated file descriptor with the same (reused) number.//// As an alternative, see the f.SyscallConn method.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)}// 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. On Unix systems, if the file descriptor is in// non-blocking mode, NewFile will attempt to return a pollable File// (one for which the SetDeadline methods work).//// After passing it to NewFile, fd may become invalid under the same// conditions described in the comments of the Fd method, and the same// constraints apply.func ( uintptr, string) *File { := kindNewFileif , := unix.IsNonblock(int()); == nil && { = kindNonBlock }returnnewFile(, , )}// newFileKind describes the kind of file to newFile.type newFileKind intconst ( kindNewFile newFileKind = iota kindOpenFile kindPipe kindNonBlock)// 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( uintptr, string, newFileKind) *File { := int()if < 0 {returnnil } := &File{&file{pfd: poll.FD{Sysfd: ,IsStream: true,ZeroReadIsEOF: true, },name: ,stdoutOrErr: == 1 || == 2, }} := == kindOpenFile || == kindPipe || == kindNonBlock// If the caller passed a non-blocking filedes (kindNonBlock), // we assume they know what they are doing so we allow it to be // used with 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 {if == kindNonBlock { .nonblock = true } 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 } }runtime.SetFinalizer(.file, (*file).close)return}// 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 openFdAt, if relevant.func openFileNolog( string, int, FileMode) (*File, error) { := falseif !supportsCreateWithStickyBit && &O_CREATE != 0 && &ModeSticky != 0 {if , := Stat(); IsNotExist() { = true } }varintfor {varerror , = syscall.Open(, |syscall.O_CLOEXEC, syscallMode())if == nil {break }// We have to check EINTR here, per issues 11180 and 39237.if == syscall.EINTR {continue }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() }returnnewFile(uintptr(), , kindOpenFile), nil}func ( *file) () error {if == nil {returnsyscall.EINVAL }if .dirinfo != nil { .dirinfo.close() .dirinfo = nil }varerrorif := .pfd.Close(); != nil {if == poll.ErrFileClosing { = ErrClosed } = &PathError{Op: "close", Path: .name, Err: } }// no need for a finalizer anymoreruntime.SetFinalizer(, nil)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 != nil {// Free cached dirinfo, so we allocate a new one if we // access this file as a directory again. See #35767 and #37161. .dirinfo.close() .dirinfo = nil } , = .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}// Readlink returns the destination of the named symbolic link.// If there is an error, it will be of type *PathError.func ( string) (string, error) {for := 128; ; *= 2 { := make([]byte, )var (interror )for { , = fixCount(syscall.Readlink(, ))if != syscall.EINTR {break } }// buffer too smallifruntime.GOOS == "aix" && == 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 newUnixDirent(, string, FileMode) (DirEntry, error) { := &unixDirent{parent: ,name: ,typ: , }if != ^FileMode(0) && !testingForceReadDirLstat {return , nil } , := lstat( + "/" + )if != nil {returnnil, } .typ = .Mode().Type() .info = return , nil}
The pages are generated with Goldsv0.5.5. (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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds.