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