github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/src/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  // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
     6  
     7  package os
     8  
     9  import (
    10  	"runtime"
    11  	"sync/atomic"
    12  	"syscall"
    13  )
    14  
    15  // File represents an open file descriptor.
    16  type File struct {
    17  	*file
    18  }
    19  
    20  // file is the real representation of *File.
    21  // The extra level of indirection ensures that no clients of os
    22  // can overwrite this data, which could cause the finalizer
    23  // to close the wrong file descriptor.
    24  type file struct {
    25  	fd      int
    26  	name    string
    27  	dirinfo *dirInfo // nil unless directory being read
    28  	nepipe  int32    // number of consecutive EPIPE in Write
    29  }
    30  
    31  // Fd returns the integer Unix file descriptor referencing the open file.
    32  // The file descriptor is valid only until f.Close is called or f is garbage collected.
    33  func (f *File) Fd() uintptr {
    34  	if f == nil {
    35  		return ^(uintptr(0))
    36  	}
    37  	return uintptr(f.fd)
    38  }
    39  
    40  // NewFile returns a new File with the given file descriptor and name.
    41  func NewFile(fd uintptr, name string) *File {
    42  	fdi := int(fd)
    43  	if fdi < 0 {
    44  		return nil
    45  	}
    46  	f := &File{&file{fd: fdi, name: name}}
    47  	runtime.SetFinalizer(f.file, (*file).close)
    48  	return f
    49  }
    50  
    51  // Auxiliary information if the File describes a directory
    52  type dirInfo struct {
    53  	buf  []byte // buffer for directory I/O
    54  	nbuf int    // length of buf; return value from Getdirentries
    55  	bufp int    // location of next record in buf.
    56  }
    57  
    58  func epipecheck(file *File, e error) {
    59  	if e == syscall.EPIPE {
    60  		if atomic.AddInt32(&file.nepipe, 1) >= 10 {
    61  			sigpipe()
    62  		}
    63  	} else {
    64  		atomic.StoreInt32(&file.nepipe, 0)
    65  	}
    66  }
    67  
    68  // DevNull is the name of the operating system's ``null device.''
    69  // On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
    70  const DevNull = "/dev/null"
    71  
    72  // OpenFile is the generalized open call; most users will use Open
    73  // or Create instead.  It opens the named file with specified flag
    74  // (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
    75  // methods on the returned File can be used for I/O.
    76  // If there is an error, it will be of type *PathError.
    77  func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
    78  	r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
    79  	if e != nil {
    80  		return nil, &PathError{"open", name, e}
    81  	}
    82  
    83  	// There's a race here with fork/exec, which we are
    84  	// content to live with.  See ../syscall/exec_unix.go.
    85  	if !supportsCloseOnExec {
    86  		syscall.CloseOnExec(r)
    87  	}
    88  
    89  	return NewFile(uintptr(r), name), nil
    90  }
    91  
    92  // Close closes the File, rendering it unusable for I/O.
    93  // It returns an error, if any.
    94  func (f *File) Close() error {
    95  	if f == nil {
    96  		return ErrInvalid
    97  	}
    98  	return f.file.close()
    99  }
   100  
   101  func (file *file) close() error {
   102  	if file == nil || file.fd < 0 {
   103  		return syscall.EINVAL
   104  	}
   105  	var err error
   106  	if e := syscall.Close(file.fd); e != nil {
   107  		err = &PathError{"close", file.name, e}
   108  	}
   109  	file.fd = -1 // so it can't be closed again
   110  
   111  	// no need for a finalizer anymore
   112  	runtime.SetFinalizer(file, nil)
   113  	return err
   114  }
   115  
   116  // Stat returns the FileInfo structure describing file.
   117  // If there is an error, it will be of type *PathError.
   118  func (f *File) Stat() (fi FileInfo, err error) {
   119  	if f == nil {
   120  		return nil, ErrInvalid
   121  	}
   122  	var stat syscall.Stat_t
   123  	err = syscall.Fstat(f.fd, &stat)
   124  	if err != nil {
   125  		return nil, &PathError{"stat", f.name, err}
   126  	}
   127  	return fileInfoFromStat(&stat, f.name), nil
   128  }
   129  
   130  // Stat returns a FileInfo describing the named file.
   131  // If there is an error, it will be of type *PathError.
   132  func Stat(name string) (fi FileInfo, err error) {
   133  	var stat syscall.Stat_t
   134  	err = syscall.Stat(name, &stat)
   135  	if err != nil {
   136  		return nil, &PathError{"stat", name, err}
   137  	}
   138  	return fileInfoFromStat(&stat, name), nil
   139  }
   140  
   141  // Lstat returns a FileInfo describing the named file.
   142  // If the file is a symbolic link, the returned FileInfo
   143  // describes the symbolic link.  Lstat makes no attempt to follow the link.
   144  // If there is an error, it will be of type *PathError.
   145  func Lstat(name string) (fi FileInfo, err error) {
   146  	var stat syscall.Stat_t
   147  	err = syscall.Lstat(name, &stat)
   148  	if err != nil {
   149  		return nil, &PathError{"lstat", name, err}
   150  	}
   151  	return fileInfoFromStat(&stat, name), nil
   152  }
   153  
   154  func (f *File) readdir(n int) (fi []FileInfo, err error) {
   155  	dirname := f.name
   156  	if dirname == "" {
   157  		dirname = "."
   158  	}
   159  	names, err := f.Readdirnames(n)
   160  	fi = make([]FileInfo, 0, len(names))
   161  	for _, filename := range names {
   162  		fip, lerr := lstat(dirname + "/" + filename)
   163  		if IsNotExist(lerr) {
   164  			// File disappeared between readdir + stat.
   165  			// Just treat it as if it didn't exist.
   166  			continue
   167  		}
   168  		if lerr != nil {
   169  			return fi, lerr
   170  		}
   171  		fi = append(fi, fip)
   172  	}
   173  	return fi, err
   174  }
   175  
   176  // Darwin and FreeBSD can't read or write 2GB+ at a time,
   177  // even on 64-bit systems. See golang.org/issue/7812.
   178  // Use 1GB instead of, say, 2GB-1, to keep subsequent
   179  // reads aligned.
   180  const (
   181  	needsMaxRW = runtime.GOOS == "darwin" || runtime.GOOS == "freebsd"
   182  	maxRW      = 1 << 30
   183  )
   184  
   185  // read reads up to len(b) bytes from the File.
   186  // It returns the number of bytes read and an error, if any.
   187  func (f *File) read(b []byte) (n int, err error) {
   188  	if needsMaxRW && len(b) > maxRW {
   189  		b = b[:maxRW]
   190  	}
   191  	return fixCount(syscall.Read(f.fd, b))
   192  }
   193  
   194  // pread reads len(b) bytes from the File starting at byte offset off.
   195  // It returns the number of bytes read and the error, if any.
   196  // EOF is signaled by a zero count with err set to nil.
   197  func (f *File) pread(b []byte, off int64) (n int, err error) {
   198  	if needsMaxRW && len(b) > maxRW {
   199  		b = b[:maxRW]
   200  	}
   201  	return fixCount(syscall.Pread(f.fd, b, off))
   202  }
   203  
   204  // write writes len(b) bytes to the File.
   205  // It returns the number of bytes written and an error, if any.
   206  func (f *File) write(b []byte) (n int, err error) {
   207  	for {
   208  		bcap := b
   209  		if needsMaxRW && len(bcap) > maxRW {
   210  			bcap = bcap[:maxRW]
   211  		}
   212  		m, err := fixCount(syscall.Write(f.fd, bcap))
   213  		n += m
   214  
   215  		// If the syscall wrote some data but not all (short write)
   216  		// or it returned EINTR, then assume it stopped early for
   217  		// reasons that are uninteresting to the caller, and try again.
   218  		if 0 < m && m < len(bcap) || err == syscall.EINTR {
   219  			b = b[m:]
   220  			continue
   221  		}
   222  
   223  		if needsMaxRW && len(bcap) != len(b) && err == nil {
   224  			b = b[m:]
   225  			continue
   226  		}
   227  
   228  		return n, err
   229  	}
   230  }
   231  
   232  // pwrite writes len(b) bytes to the File starting at byte offset off.
   233  // It returns the number of bytes written and an error, if any.
   234  func (f *File) pwrite(b []byte, off int64) (n int, err error) {
   235  	if needsMaxRW && len(b) > maxRW {
   236  		b = b[:maxRW]
   237  	}
   238  	return fixCount(syscall.Pwrite(f.fd, b, off))
   239  }
   240  
   241  // seek sets the offset for the next Read or Write on file to offset, interpreted
   242  // according to whence: 0 means relative to the origin of the file, 1 means
   243  // relative to the current offset, and 2 means relative to the end.
   244  // It returns the new offset and an error, if any.
   245  func (f *File) seek(offset int64, whence int) (ret int64, err error) {
   246  	return syscall.Seek(f.fd, offset, whence)
   247  }
   248  
   249  // Truncate changes the size of the named file.
   250  // If the file is a symbolic link, it changes the size of the link's target.
   251  // If there is an error, it will be of type *PathError.
   252  func Truncate(name string, size int64) error {
   253  	if e := syscall.Truncate(name, size); e != nil {
   254  		return &PathError{"truncate", name, e}
   255  	}
   256  	return nil
   257  }
   258  
   259  // Remove removes the named file or directory.
   260  // If there is an error, it will be of type *PathError.
   261  func Remove(name string) error {
   262  	// System call interface forces us to know
   263  	// whether name is a file or directory.
   264  	// Try both: it is cheaper on average than
   265  	// doing a Stat plus the right one.
   266  	e := syscall.Unlink(name)
   267  	if e == nil {
   268  		return nil
   269  	}
   270  	e1 := syscall.Rmdir(name)
   271  	if e1 == nil {
   272  		return nil
   273  	}
   274  
   275  	// Both failed: figure out which error to return.
   276  	// OS X and Linux differ on whether unlink(dir)
   277  	// returns EISDIR, so can't use that.  However,
   278  	// both agree that rmdir(file) returns ENOTDIR,
   279  	// so we can use that to decide which error is real.
   280  	// Rmdir might also return ENOTDIR if given a bad
   281  	// file path, like /etc/passwd/foo, but in that case,
   282  	// both errors will be ENOTDIR, so it's okay to
   283  	// use the error from unlink.
   284  	if e1 != syscall.ENOTDIR {
   285  		e = e1
   286  	}
   287  	return &PathError{"remove", name, e}
   288  }
   289  
   290  // basename removes trailing slashes and the leading directory name from path name
   291  func basename(name string) string {
   292  	i := len(name) - 1
   293  	// Remove trailing slashes
   294  	for ; i > 0 && name[i] == '/'; i-- {
   295  		name = name[:i]
   296  	}
   297  	// Remove leading directory name
   298  	for i--; i >= 0; i-- {
   299  		if name[i] == '/' {
   300  			name = name[i+1:]
   301  			break
   302  		}
   303  	}
   304  
   305  	return name
   306  }
   307  
   308  // TempDir returns the default directory to use for temporary files.
   309  func TempDir() string {
   310  	dir := Getenv("TMPDIR")
   311  	if dir == "" {
   312  		if runtime.GOOS == "android" {
   313  			dir = "/data/local/tmp"
   314  		} else {
   315  			dir = "/tmp"
   316  		}
   317  	}
   318  	return dir
   319  }
   320  
   321  // Link creates newname as a hard link to the oldname file.
   322  // If there is an error, it will be of type *LinkError.
   323  func Link(oldname, newname string) error {
   324  	e := syscall.Link(oldname, newname)
   325  	if e != nil {
   326  		return &LinkError{"link", oldname, newname, e}
   327  	}
   328  	return nil
   329  }
   330  
   331  // Symlink creates newname as a symbolic link to oldname.
   332  // If there is an error, it will be of type *LinkError.
   333  func Symlink(oldname, newname string) error {
   334  	e := syscall.Symlink(oldname, newname)
   335  	if e != nil {
   336  		return &LinkError{"symlink", oldname, newname, e}
   337  	}
   338  	return nil
   339  }