Source File
file_unix.go
Belonging Package
os
// 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 ( string) string {return}func (, 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", , , }} else if == || !SameFile(, ) {return &LinkError{"rename", , , syscall.EEXIST}}}= ignoringEINTR(func() error {return syscall.Rename(, )})if != nil {return &LinkError{"rename", , , }}return nil}// 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.FDname stringdirinfo atomic.Pointer[dirInfo] // nil unless directory being readnonblock bool // whether we set nonblocking modestdoutOrErr bool // whether this is stdout or stderrappendMode 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 [File.SetDeadline]// methods to stop working.// Because file descriptors can be reused, the returned file descriptor may// only be closed through the [File.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()}return uintptr(.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 {:= int()if < 0 {return nil}, := 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 ( int, string) *File {if < 0 {panic("invalid FD")}return newFile(, , 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 ( 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 {switch runtime.GOOS {case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd":var syscall.Stat_t:= ignoringEINTR(func() error {return syscall.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}} else if := 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}func () // 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 ( *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".const DevNull = "/dev/null"// openFileNolog is the Unix implementation of OpenFile.// Changes here should be reflected in openDirAt and openDirNolog, if relevant.func ( 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 {return nil, &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 ( string) (*File, error) {var (intpoll.SysFileerror)ignoringEINTR(func() error {, , = open(, O_RDONLY|syscall.O_CLOEXEC|syscall.O_DIRECTORY, 0)return})if != nil {return nil, &PathError{Op: "open", Path: , Err: }}if !supportsCloseOnExec {syscall.CloseOnExec()}:= newFile(, , kindNoPoll, false).pfd.SysFile =return , nil}func ( *file) () error {if == nil {return syscall.EINVAL}if := .dirinfo.Swap(nil); != nil {.close()}var errorif := .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.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 {return syscall.Truncate(, )})if != nil {return &PathError{Op: "truncate", Path: , Err: }}return nil}// 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 {return syscall.Unlink()})if == nil {return nil}:= ignoringEINTR(func() error {return syscall.Rmdir()})if == nil {return nil}// 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 () string {:= Getenv("TMPDIR")if == "" {if runtime.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 {return syscall.Link(, )})if != nil {return &LinkError{"link", , , }}return nil}// 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 {return syscall.Symlink(, )})if != nil {return &LinkError{"symlink", , , }}return nil}func ( string) (string, error) {for := 128; ; *= 2 {:= make([]byte, ), := ignoringEINTR2(func() (int, error) {return fixCount(syscall.Readlink(, ))})// buffer too smallif (runtime.GOOS == "aix" || runtime.GOOS == "wasip1") && == syscall.ERANGE {continue}if != nil {return "", &PathError{Op: "readlink", Path: , Err: }}if < {return string([0:]), nil}}}type unixDirent struct {parent stringname stringtyp FileModeinfo 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}return lstat(.parent + "/" + .name)}func ( *unixDirent) () string {return fs.FormatDirEntry()}func (, string, FileMode) (DirEntry, error) {:= &unixDirent{parent: ,name: ,typ: ,}if != ^FileMode(0) && !testingForceReadDirLstat {return , nil}, := lstat( + "/" + )if != nil {return nil,}.typ = .Mode().Type().info =return , nil}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)