file_anyos.mx raw

   1  //go:build !baremetal && !js && !wasm_unknown && !nintendoswitch
   2  
   3  // Portions copyright 2009-2024 The Go Authors. All rights reserved.
   4  // Use of this source code is governed by a BSD-style
   5  // license that can be found in the LICENSE file.
   6  
   7  package os
   8  
   9  import (
  10  	"io"
  11  	"syscall"
  12  )
  13  
  14  func init() {
  15  	// Mount the host filesystem at the root directory. This is what most
  16  	// programs will be expecting.
  17  	Mount("/", unixFilesystem{})
  18  }
  19  
  20  // Stdin, Stdout, and Stderr are open Files pointing to the standard input,
  21  // standard output, and standard error file descriptors.
  22  var (
  23  	Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
  24  	Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
  25  	Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
  26  )
  27  
  28  // isOS indicates whether we're running on a real operating system with
  29  // filesystem support.
  30  const isOS = true
  31  
  32  // Chdir changes the current working directory to the named directory.
  33  // If there is an error, it will be of type *PathError.
  34  func Chdir(dir string) error {
  35  	if e := syscall.Chdir(dir); e != nil {
  36  		return &PathError{Op: "chdir", Path: dir, Err: e}
  37  	}
  38  	return nil
  39  }
  40  
  41  // Rename renames (moves) oldpath to newpath.
  42  // If newpath already exists and is not a directory, Rename replaces it.
  43  // OS-specific restrictions may apply when oldpath and newpath are in different directories.
  44  // If there is an error, it will be of type *LinkError.
  45  func Rename(oldpath, newpath string) error {
  46  	return rename(oldpath, newpath)
  47  }
  48  
  49  // unixFilesystem is an empty handle for a Unix/Linux filesystem. All operations
  50  // are relative to the current working directory.
  51  type unixFilesystem struct {
  52  }
  53  
  54  func (fs unixFilesystem) Mkdir(path string, perm FileMode) error {
  55  	return handleSyscallError(syscall.Mkdir(path, uint32(perm)))
  56  }
  57  
  58  func (fs unixFilesystem) Remove(path string) error {
  59  	// System call interface forces us to know
  60  	// whether name is a file or directory.
  61  	// Try both: it is cheaper on average than
  62  	// doing a Stat plus the right one.
  63  	e := handleSyscallError(syscall.Unlink(path))
  64  	if e == nil {
  65  		return nil
  66  	}
  67  	e1 := handleSyscallError(syscall.Rmdir(path))
  68  	if e1 == nil {
  69  		return nil
  70  	}
  71  
  72  	// Both failed: figure out which error to return.
  73  	// OS X and Linux differ on whether unlink(dir)
  74  	// returns EISDIR, so can't use that. However,
  75  	// both agree that rmdir(file) returns ENOTDIR,
  76  	// so we can use that to decide which error is real.
  77  	// Rmdir might also return ENOTDIR if given a bad
  78  	// file path, like /etc/passwd/foo, but in that case,
  79  	// both errors will be ENOTDIR, so it's okay to
  80  	// use the error from unlink.
  81  	if e1 != syscall.ENOTDIR {
  82  		e = e1
  83  	}
  84  	return &PathError{Op: "remove", Path: path, Err: e}
  85  }
  86  
  87  func (fs unixFilesystem) OpenFile(path string, flag int, perm FileMode) (uintptr, error) {
  88  	fp, err := syscall.Open(path, flag, uint32(perm))
  89  	return uintptr(fp), handleSyscallError(err)
  90  }
  91  
  92  // unixFileHandle is a Unix file pointer with associated methods that implement
  93  // the FileHandle interface.
  94  type unixFileHandle uintptr
  95  
  96  // Read reads up to len(b) bytes from the File. It returns the number of bytes
  97  // read and any error encountered. At end of file, Read returns 0, io.EOF.
  98  func (f unixFileHandle) Read(b []byte) (n int, err error) {
  99  	n, err = syscall.Read(syscallFd(f), b)
 100  	// In case of EISDIR, n == -1.
 101  	// This breaks the assumption that n always represent the number of read bytes.
 102  	if err == syscall.EISDIR {
 103  		n = 0
 104  	}
 105  	err = handleSyscallError(err)
 106  	if n == 0 && len(b) > 0 && err == nil {
 107  		err = io.EOF
 108  	}
 109  	return
 110  }
 111  
 112  // Write writes len(b) bytes to the File. It returns the number of bytes written
 113  // and an error, if any. Write returns a non-nil error when n != len(b).
 114  func (f unixFileHandle) Write(b []byte) (n int, err error) {
 115  	n, err = syscall.Write(syscallFd(f), b)
 116  	err = handleSyscallError(err)
 117  	return
 118  }
 119  
 120  // Close closes the File, rendering it unusable for I/O.
 121  func (f unixFileHandle) Close() error {
 122  	return handleSyscallError(syscall.Close(syscallFd(f)))
 123  }
 124  
 125  func (f unixFileHandle) Fd() uintptr {
 126  	return uintptr(f)
 127  }
 128  
 129  // Chmod changes the mode of the named file to mode.
 130  // If the file is a symbolic link, it changes the mode of the link's target.
 131  // If there is an error, it will be of type *PathError.
 132  //
 133  // A different subset of the mode bits are used, depending on the
 134  // operating system.
 135  //
 136  // On Unix, the mode's permission bits, ModeSetuid, ModeSetgid, and
 137  // ModeSticky are used.
 138  //
 139  // On Windows, only the 0200 bit (owner writable) of mode is used; it
 140  // controls whether the file's read-only attribute is set or cleared.
 141  // The other bits are currently unused. For compatibility with Go 1.12
 142  // and earlier, use a non-zero mode. Use mode 0400 for a read-only
 143  // file and 0600 for a readable+writable file.
 144  func Chmod(name string, mode FileMode) error {
 145  	longName := fixLongPath(name)
 146  	e := ignoringEINTR(func() error {
 147  		return syscall.Chmod(longName, syscallMode(mode))
 148  	})
 149  	if e != nil {
 150  		return &PathError{Op: "chmod", Path: name, Err: e}
 151  	}
 152  	return nil
 153  }
 154  
 155  // Chown changes the numeric uid and gid of the named file.
 156  // If the file is a symbolic link, it changes the uid and gid of the link's target.
 157  // A uid or gid of -1 means to not change that value.
 158  // If there is an error, it will be of type *PathError.
 159  func Chown(name string, uid, gid int) error {
 160  	e := ignoringEINTR(func() error {
 161  		return syscall.Chown(name, uid, gid)
 162  	})
 163  	if e != nil {
 164  		return &PathError{Op: "chown", Path: name, Err: e}
 165  	}
 166  	return nil
 167  }
 168  
 169  // ignoringEINTR makes a function call and repeats it if it returns an
 170  // EINTR error. This appears to be required even though we install all
 171  // signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
 172  // Also #20400 and #36644 are issues in which a signal handler is
 173  // installed without setting SA_RESTART. None of these are the common case,
 174  // but there are enough of them that it seems that we can't avoid
 175  // an EINTR loop.
 176  func ignoringEINTR(fn func() error) error {
 177  	for {
 178  		err := fn()
 179  		if err != syscall.EINTR {
 180  			return err
 181  		}
 182  	}
 183  }
 184  
 185  // handleSyscallError converts syscall errors into regular os package errors.
 186  // The err parameter must be either nil or of type syscall.Errno.
 187  func handleSyscallError(err error) error {
 188  	if err == nil {
 189  		return nil
 190  	}
 191  	switch err.(syscall.Errno) {
 192  	case syscall.EEXIST:
 193  		return ErrExist
 194  	case syscall.ENOENT:
 195  		return ErrNotExist
 196  	default:
 197  		return err
 198  	}
 199  }
 200  
 201  // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
 202  func syscallMode(i FileMode) (o uint32) {
 203  	o |= uint32(i.Perm())
 204  	if i&ModeSetuid != 0 {
 205  		o |= syscall.S_ISUID
 206  	}
 207  	if i&ModeSetgid != 0 {
 208  		o |= syscall.S_ISGID
 209  	}
 210  	if i&ModeSticky != 0 {
 211  		o |= syscall.S_ISVTX
 212  	}
 213  	// No mapping for Go's ModeTemporary (plan9 only).
 214  	return
 215  }
 216