...

Source file src/os/file_unix.go

Documentation: os

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

View as plain text