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