file.mx raw

   1  // Portions 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  // This file was originally copied from Go, see:
   6  // https://github.com/golang/go/blob/master/src/os/file.go
   7  //
   8  // Some of the code inherited from Go is not used anymore in Moxie, but we keep
   9  // changes to a minimum to help simplify bringing changes (e.g. the lstat global
  10  // is not used here anymore, but we might need it if we add tests from Go in
  11  // this package).
  12  
  13  // Package os implements a subset of the Go "os" package. See
  14  // https://godoc.org/os for details.
  15  //
  16  // Note that the current implementation is blocking. This limitation should be
  17  // removed in a future version.
  18  package os
  19  
  20  import (
  21  	"errors"
  22  	"io"
  23  	"io/fs"
  24  	"runtime"
  25  	"syscall"
  26  	"time"
  27  )
  28  
  29  // Seek whence values.
  30  //
  31  // Deprecated: Use io.SeekStart, io.SeekCurrent, and io.SeekEnd.
  32  const (
  33  	SEEK_SET int = io.SeekStart
  34  	SEEK_CUR int = io.SeekCurrent
  35  	SEEK_END int = io.SeekEnd
  36  )
  37  
  38  // lstat is overridden in tests.
  39  var lstat = Lstat
  40  
  41  // Mkdir creates a directory. If the operation fails, it will return an error of
  42  // type *PathError.
  43  func Mkdir(path string, perm FileMode) error {
  44  	fs, suffix := findMount(path)
  45  	if fs == nil {
  46  		return &PathError{Op: "mkdir", Path: path, Err: ErrNotExist}
  47  	}
  48  	err := fs.Mkdir(suffix, perm)
  49  	if err != nil {
  50  		return &PathError{Op: "mkdir", Path: path, Err: err}
  51  	}
  52  	return nil
  53  }
  54  
  55  // Many functions in package syscall return a count of -1 instead of 0.
  56  // Using fixCount(call()) instead of call() corrects the count.
  57  func fixCount(n int, err error) (int, error) {
  58  	if n < 0 {
  59  		n = 0
  60  	}
  61  	return n, err
  62  }
  63  
  64  // Remove removes a file or (empty) directory. If the operation fails, it will
  65  // return an error of type *PathError.
  66  func Remove(path string) error {
  67  	fs, suffix := findMount(path)
  68  	if fs == nil {
  69  		return &PathError{Op: "remove", Path: path, Err: ErrNotExist}
  70  	}
  71  	err := fs.Remove(suffix)
  72  	if err != nil {
  73  		return err
  74  	}
  75  	return nil
  76  }
  77  
  78  // Name returns the name of the file with which it was opened.
  79  func (f *File) Name() string {
  80  	return f.name
  81  }
  82  
  83  // OpenFile opens the named file. If the operation fails, the returned error
  84  // will be of type *PathError.
  85  func OpenFile(name string, flag int, perm FileMode) (*File, error) {
  86  	fs, suffix := findMount(name)
  87  	if fs == nil {
  88  		return nil, &PathError{Op: "open", Path: name, Err: ErrNotExist}
  89  	}
  90  	handle, err := fs.OpenFile(suffix, flag, perm)
  91  	if err != nil {
  92  		return nil, &PathError{Op: "open", Path: name, Err: err}
  93  	}
  94  	f := NewFile(handle, name)
  95  	f.appendMode = (flag & O_APPEND) != 0
  96  	return f, nil
  97  }
  98  
  99  // Open opens the file named for reading.
 100  func Open(name string) (*File, error) {
 101  	return OpenFile(name, O_RDONLY, 0)
 102  }
 103  
 104  // Create creates the named file, overwriting it if it already exists.
 105  func Create(name string) (*File, error) {
 106  	return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
 107  }
 108  
 109  // Read reads up to len(b) bytes from the File. It returns the number of bytes
 110  // read and any error encountered. At end of file, Read returns 0, io.EOF.
 111  func (f *File) Read(b []byte) (n int, err error) {
 112  	if f.handle == nil {
 113  		err = ErrClosed
 114  	} else {
 115  		n, err = f.handle.Read(b)
 116  	}
 117  	// TODO: want to always wrap, like upstream, but ReadFile() compares against exactly io.EOF?
 118  	if err != nil && err != io.EOF {
 119  		err = &PathError{Op: "read", Path: f.name, Err: err}
 120  	}
 121  	return
 122  }
 123  
 124  var errNegativeOffset = errors.New("negative offset")
 125  
 126  // ReadAt reads up to len(b) bytes from the File at the given absolute offset.
 127  // It returns the number of bytes read and any error encountered, possible io.EOF.
 128  // At end of file, Read returns 0, io.EOF.
 129  func (f *File) ReadAt(b []byte, offset int64) (n int, err error) {
 130  	if offset < 0 {
 131  		return 0, &PathError{Op: "readat", Path: f.name, Err: errNegativeOffset}
 132  	}
 133  	if f.handle == nil {
 134  		return 0, &PathError{Op: "readat", Path: f.name, Err: ErrClosed}
 135  	}
 136  
 137  	for len(b) > 0 {
 138  		m, e := f.handle.ReadAt(b, offset)
 139  		if e != nil {
 140  			// TODO: want to always wrap, like upstream, but TestReadAtEOF compares against exactly io.EOF?
 141  			if e != io.EOF {
 142  				err = &PathError{Op: "readat", Path: f.name, Err: e}
 143  			} else {
 144  				err = e
 145  			}
 146  			break
 147  		}
 148  		n += m
 149  		b = b[m:]
 150  		offset += int64(m)
 151  	}
 152  
 153  	return
 154  }
 155  
 156  // Write writes len(b) bytes to the File. It returns the number of bytes written
 157  // and an error, if any. Write returns a non-nil error when n != len(b).
 158  func (f *File) Write(b []byte) (n int, err error) {
 159  	if f.handle == nil {
 160  		err = ErrClosed
 161  	} else {
 162  		n, err = f.handle.Write(b)
 163  	}
 164  	if err != nil {
 165  		err = &PathError{Op: "write", Path: f.name, Err: err}
 166  	}
 167  	return
 168  }
 169  
 170  // WriteString is like Write, but writes the contents of string s rather than a
 171  // slice of bytes.
 172  func (f *File) WriteString(s string) (n int, err error) {
 173  	return f.Write([]byte(s))
 174  }
 175  
 176  var errWriteAtInAppendMode = errors.New("os: invalid use of WriteAt on file opened with O_APPEND")
 177  
 178  // WriteAt writes len(b) bytes to the File starting at byte offset off.
 179  // It returns the number of bytes written and an error, if any.
 180  // WriteAt returns a non-nil error when n != len(b).
 181  //
 182  // If file was opened with the O_APPEND flag, WriteAt returns an error.
 183  func (f *File) WriteAt(b []byte, offset int64) (n int, err error) {
 184  	switch {
 185  	case offset < 0:
 186  		return 0, &PathError{Op: "writeat", Path: f.name, Err: errNegativeOffset}
 187  	case f.handle == nil:
 188  		return 0, &PathError{Op: "writeat", Path: f.name, Err: ErrClosed}
 189  	case f.appendMode:
 190  		// Go does not wrap this error but it would be more consistent
 191  		// if it did.
 192  		return 0, errWriteAtInAppendMode
 193  	}
 194  	for len(b) > 0 {
 195  		m, e := f.handle.WriteAt(b, offset)
 196  		if e != nil {
 197  			err = &PathError{Op: "writeat", Path: f.name, Err: e}
 198  			break
 199  		}
 200  		n += m
 201  		b = b[m:]
 202  		offset += int64(m)
 203  	}
 204  	return
 205  }
 206  
 207  // Close closes the File, rendering it unusable for I/O.
 208  func (f *File) Close() (err error) {
 209  	if f.handle == nil {
 210  		err = ErrClosed
 211  	} else {
 212  		// Some platforms manage extra state other than the system handle which
 213  		// needs to be released when the file is closed. For example, darwin
 214  		// files have a DIR object holding a dup of the file descriptor, and
 215  		// linux files hold a buffer which needs to be released to a pool.
 216  		//
 217  		// These platform-specific logic is provided by the (*file).close method
 218  		// which is why we do not call the handle's Close method directly.
 219  		err = f.file.close()
 220  		if err == nil {
 221  			f.handle = nil
 222  		}
 223  	}
 224  	if err != nil {
 225  		err = &PathError{Op: "close", Path: f.name, Err: err}
 226  	}
 227  	return
 228  }
 229  
 230  // Seek sets the offset for the next Read or Write on file to offset, interpreted
 231  // according to whence: 0 means relative to the origin of the file, 1 means
 232  // relative to the current offset, and 2 means relative to the end.
 233  // It returns the new offset and an error, if any.
 234  // The behavior of Seek on a file opened with O_APPEND is not specified.
 235  //
 236  // If f is a directory, the behavior of Seek varies by operating
 237  // system; you can seek to the beginning of the directory on Unix-like
 238  // operating systems, but not on Windows.
 239  func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
 240  	if f.handle == nil {
 241  		err = ErrClosed
 242  	} else {
 243  		ret, err = f.handle.Seek(offset, whence)
 244  	}
 245  	if err != nil {
 246  		err = &PathError{Op: "seek", Path: f.name, Err: err}
 247  	}
 248  	return
 249  }
 250  
 251  func (f *File) SyscallConn() (conn syscall.RawConn, err error) {
 252  	if f.handle == nil {
 253  		err = ErrClosed
 254  	} else {
 255  		err = ErrNotImplemented
 256  	}
 257  	return
 258  }
 259  
 260  // SetDeadline sets the read and write deadlines for a File.
 261  // Calls to SetDeadline for files that do not support deadlines will return ErrNoDeadline
 262  // This stub always returns ErrNoDeadline.
 263  // A zero value for t means I/O operations will not time out.
 264  func (f *File) SetDeadline(t time.Time) error {
 265  	if f.handle == nil {
 266  		return ErrClosed
 267  	}
 268  	return f.setDeadline(t)
 269  }
 270  
 271  // SetReadDeadline sets the deadline for future Read calls and any
 272  // currently-blocked Read call.
 273  func (f *File) SetReadDeadline(t time.Time) error {
 274  	return f.setReadDeadline(t)
 275  }
 276  
 277  // SetWriteDeadline sets the deadline for any future Write calls and any
 278  // currently-blocked Write call.
 279  func (f *File) SetWriteDeadline(t time.Time) error {
 280  	return f.setWriteDeadline(t)
 281  }
 282  
 283  // fd is an internal interface that is used to try a type assertion in order to
 284  // call the Fd() method of the underlying file handle if it is implemented.
 285  type fd interface {
 286  	Fd() uintptr
 287  }
 288  
 289  // Fd returns the file handle referencing the open file.
 290  func (f *File) Fd() uintptr {
 291  	handle, ok := f.handle.(fd)
 292  	if ok {
 293  		return handle.Fd()
 294  	}
 295  	return ^uintptr(0)
 296  }
 297  
 298  // Sync commits the current contents of the file to stable storage.
 299  // Typically, this means flushing the file system's in-memory copy of recently
 300  // written data to disk.
 301  func (f *File) Sync() (err error) {
 302  	if f.handle == nil {
 303  		err = ErrClosed
 304  	} else {
 305  		err = f.handle.Sync()
 306  	}
 307  	return
 308  }
 309  
 310  // Chmod changes the mode of the file to mode. If there is an error, it will be
 311  // of type *PathError.
 312  func (f *File) Chmod(mode FileMode) (err error) {
 313  	if f.handle == nil {
 314  		err = ErrClosed
 315  	} else {
 316  		err = f.chmod(mode)
 317  	}
 318  	return
 319  }
 320  
 321  // Chdir changes the current working directory to the file, which must be a
 322  // directory. If there is an error, it will be of type *PathError.
 323  func (f *File) Chdir() (err error) {
 324  	if f.handle == nil {
 325  		err = ErrClosed
 326  	} else {
 327  		err = f.chdir()
 328  	}
 329  	return
 330  }
 331  
 332  // LinkError records an error during a link or symlink or rename system call and
 333  // the paths that caused it.
 334  type LinkError struct {
 335  	Op  string
 336  	Old string
 337  	New string
 338  	Err error
 339  }
 340  
 341  func (e *LinkError) Error() string {
 342  	return e.Op + " " + e.Old + " " + e.New + ": " + e.Err.Error()
 343  }
 344  
 345  func (e *LinkError) Unwrap() error {
 346  	return e.Err
 347  }
 348  
 349  // OpenFile flag values.
 350  const (
 351  	O_RDONLY int = syscall.O_RDONLY
 352  	O_WRONLY int = syscall.O_WRONLY
 353  	O_RDWR   int = syscall.O_RDWR
 354  	O_APPEND int = syscall.O_APPEND
 355  	O_CREATE int = syscall.O_CREAT
 356  	O_EXCL   int = syscall.O_EXCL
 357  	O_SYNC   int = syscall.O_SYNC
 358  	O_TRUNC  int = syscall.O_TRUNC
 359  )
 360  
 361  func Getwd() (string, error) {
 362  	return syscall.Getwd()
 363  }
 364  
 365  // TempDir returns the default directory to use for temporary files.
 366  //
 367  // On Unix systems, it returns $TMPDIR if non-empty, else /tmp.
 368  // On Windows, it uses GetTempPath, returning the first non-empty
 369  // value from %TMP%, %TEMP%, %USERPROFILE%, or the Windows directory.
 370  //
 371  // The directory is neither guaranteed to exist nor have accessible
 372  // permissions.
 373  func TempDir() string {
 374  	return tempDir()
 375  }
 376  
 377  // UserHomeDir returns the current user's home directory.
 378  //
 379  // On Unix, including macOS, it returns the $HOME environment variable.
 380  // On Windows, it returns %USERPROFILE%.
 381  // On Plan 9, it returns the $home environment variable.
 382  func UserHomeDir() (string, error) {
 383  	env, enverr := "HOME", "$HOME"
 384  	switch runtime.GOOS {
 385  	case "windows":
 386  		env, enverr = "USERPROFILE", "%userprofile%"
 387  	case "plan9":
 388  		env, enverr = "home", "$home"
 389  	}
 390  	if v := Getenv(env); v != "" {
 391  		return v, nil
 392  	}
 393  	// On some geese the home directory is not always defined.
 394  	switch runtime.GOOS {
 395  	case "android":
 396  		return "/sdcard", nil
 397  	case "ios":
 398  		return "/", nil
 399  	}
 400  	return "", errors.New(enverr + " is not defined")
 401  }
 402  
 403  type (
 404  	FileMode = fs.FileMode
 405  	FileInfo = fs.FileInfo
 406  )
 407  
 408  // The followings are copied from Go 1.16 or 1.17 official implementation:
 409  // https://github.com/golang/go/blob/go1.16/src/os/file.go
 410  
 411  // DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir.
 412  //
 413  // Note that DirFS("/prefix") only guarantees that the Open calls it makes to the
 414  // operating system will begin with "/prefix": DirFS("/prefix").Open("file") is the
 415  // same as os.Open("/prefix/file"). So if /prefix/file is a symbolic link pointing outside
 416  // the /prefix tree, then using DirFS does not stop the access any more than using
 417  // os.Open does. DirFS is therefore not a general substitute for a chroot-style security
 418  // mechanism when the directory tree contains arbitrary content.
 419  func DirFS(dir string) fs.FS {
 420  	return dirFS(dir)
 421  }
 422  
 423  func containsAny(s, chars string) bool {
 424  	for i := 0; i < len(s); i++ {
 425  		for j := 0; j < len(chars); j++ {
 426  			if s[i] == chars[j] {
 427  				return true
 428  			}
 429  		}
 430  	}
 431  	return false
 432  }
 433  
 434  type dirFS string
 435  
 436  func (dir dirFS) Open(name string) (fs.File, error) {
 437  	if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
 438  		return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid}
 439  	}
 440  	f, err := Open(string(dir) + "/" + name)
 441  	if err != nil {
 442  		return nil, err // nil fs.File
 443  	}
 444  	return f, nil
 445  }
 446  
 447  func (dir dirFS) Stat(name string) (fs.FileInfo, error) {
 448  	if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
 449  		return nil, &PathError{Op: "stat", Path: name, Err: ErrInvalid}
 450  	}
 451  	f, err := Stat(string(dir) + "/" + name)
 452  	if err != nil {
 453  		return nil, err
 454  	}
 455  	return f, nil
 456  }
 457  
 458  // ReadFile reads the named file and returns the contents.
 459  // A successful call returns err == nil, not err == EOF.
 460  // Because ReadFile reads the whole file, it does not treat an EOF from Read
 461  // as an error to be reported.
 462  func ReadFile(name string) ([]byte, error) {
 463  	f, err := Open(name)
 464  	if err != nil {
 465  		return nil, err
 466  	}
 467  	defer f.Close()
 468  
 469  	var size int
 470  	if info, err := f.Stat(); err == nil {
 471  		size64 := info.Size()
 472  		if int64(int(size64)) == size64 {
 473  			size = int(size64)
 474  		}
 475  	}
 476  	size++ // one byte for final read at EOF
 477  
 478  	// If a file claims a small size, read at least 512 bytes.
 479  	// In particular, files in Linux's /proc claim size 0 but
 480  	// then do not work right if read in small pieces,
 481  	// so an initial read of 1 byte would not work correctly.
 482  	if size < 512 {
 483  		size = 512
 484  	}
 485  
 486  	data := make([]byte, 0, size)
 487  	for {
 488  		if len(data) >= cap(data) {
 489  			d := append(data[:cap(data)], 0)
 490  			data = d[:len(data)]
 491  		}
 492  		n, err := f.Read(data[len(data):cap(data)])
 493  		data = data[:len(data)+n]
 494  		if err != nil {
 495  			if err == io.EOF {
 496  				err = nil
 497  			}
 498  			return data, err
 499  		}
 500  	}
 501  }
 502  
 503  // WriteFile writes data to the named file, creating it if necessary.
 504  // If the file does not exist, WriteFile creates it with permissions perm (before umask);
 505  // otherwise WriteFile truncates it before writing, without changing permissions.
 506  func WriteFile(name string, data []byte, perm FileMode) error {
 507  	f, err := OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, perm)
 508  	if err != nil {
 509  		return err
 510  	}
 511  	_, err = f.Write(data)
 512  	if err1 := f.Close(); err1 != nil && err == nil {
 513  		err = err1
 514  	}
 515  	return err
 516  }
 517  
 518  // The defined file mode bits are the most significant bits of the FileMode.
 519  // The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
 520  // The values of these bits should be considered part of the public API and
 521  // may be used in wire protocols or disk representations: they must not be
 522  // changed, although new bits might be added.
 523  const (
 524  	// The single letters are the abbreviations
 525  	// used by the String method's formatting.
 526  	ModeDir        = fs.ModeDir        // d: is a directory
 527  	ModeAppend     = fs.ModeAppend     // a: append-only
 528  	ModeExclusive  = fs.ModeExclusive  // l: exclusive use
 529  	ModeTemporary  = fs.ModeTemporary  // T: temporary file; Plan 9 only
 530  	ModeSymlink    = fs.ModeSymlink    // L: symbolic link
 531  	ModeDevice     = fs.ModeDevice     // D: device file
 532  	ModeNamedPipe  = fs.ModeNamedPipe  // p: named pipe (FIFO)
 533  	ModeSocket     = fs.ModeSocket     // S: Unix domain socket
 534  	ModeSetuid     = fs.ModeSetuid     // u: setuid
 535  	ModeSetgid     = fs.ModeSetgid     // g: setgid
 536  	ModeCharDevice = fs.ModeCharDevice // c: Unix character device, when ModeDevice is set
 537  	ModeSticky     = fs.ModeSticky     // t: sticky
 538  	ModeIrregular  = fs.ModeIrregular  // ?: non-regular file; nothing else is known about this file
 539  
 540  	// Mask for the type bits. For regular files, none will be set.
 541  	ModeType = fs.ModeType
 542  
 543  	ModePerm = fs.ModePerm // Unix permission bits, 0o777
 544  )
 545