os: implement virtual filesystem support
This allows applications to mount filesystems in the os package. This is useful for mounting external flash filesystems, for example.
Этот коммит содержится в:
		
							родитель
							
								
									e907db1481
								
							
						
					
					
						коммит
						6bcb40fe01
					
				
					 8 изменённых файлов: 336 добавлений и 95 удалений
				
			
		
							
								
								
									
										155
									
								
								src/os/file.go
									
										
									
									
									
								
							
							
						
						
									
										155
									
								
								src/os/file.go
									
										
									
									
									
								
							| 
						 | 
					@ -10,49 +10,119 @@ import (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Portable analogs of some common system call errors.
 | 
					// Portable analogs of some common system call errors.
 | 
				
			||||||
 | 
					// Note that these are exported for use in the Filesystem interface.
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	errUnsupported = errors.New("operation not supported")
 | 
						ErrUnsupported    = errors.New("operation not supported")
 | 
				
			||||||
	notImplemented = errors.New("os: not implemented")
 | 
						ErrNotImplemented = errors.New("operation not implemented")
 | 
				
			||||||
 | 
						ErrNotExist       = errors.New("file not found")
 | 
				
			||||||
 | 
						ErrExist          = errors.New("file exists")
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
 | 
					// Mkdir creates a directory. If the operation fails, it will return an error of
 | 
				
			||||||
// standard output, and standard error file descriptors.
 | 
					// type *PathError.
 | 
				
			||||||
var (
 | 
					func Mkdir(path string, perm FileMode) error {
 | 
				
			||||||
	Stdin  = &File{0, "/dev/stdin"}
 | 
						fs, suffix := findMount(path)
 | 
				
			||||||
	Stdout = &File{1, "/dev/stdout"}
 | 
						if fs == nil {
 | 
				
			||||||
	Stderr = &File{2, "/dev/stderr"}
 | 
							return &PathError{"mkdir", path, ErrNotExist}
 | 
				
			||||||
)
 | 
						}
 | 
				
			||||||
 | 
						err := fs.Mkdir(suffix, perm)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return &PathError{"mkdir", path, err}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Remove removes a file or (empty) directory. If the operation fails, it will
 | 
				
			||||||
 | 
					// return an error of type *PathError.
 | 
				
			||||||
 | 
					func Remove(path string) error {
 | 
				
			||||||
 | 
						fs, suffix := findMount(path)
 | 
				
			||||||
 | 
						if fs == nil {
 | 
				
			||||||
 | 
							return &PathError{"remove", path, ErrNotExist}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err := fs.Remove(suffix)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return &PathError{"remove", path, err}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// File represents an open file descriptor.
 | 
					// File represents an open file descriptor.
 | 
				
			||||||
type File struct {
 | 
					type File struct {
 | 
				
			||||||
	fd   uintptr
 | 
						handle FileHandle
 | 
				
			||||||
	name   string
 | 
						name   string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Name returns the name of the file with which it was opened.
 | 
				
			||||||
 | 
					func (f *File) Name() string {
 | 
				
			||||||
 | 
						return f.name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// OpenFile opens the named file. If the operation fails, the returned error
 | 
				
			||||||
 | 
					// will be of type *PathError.
 | 
				
			||||||
 | 
					func OpenFile(name string, flag int, perm FileMode) (*File, error) {
 | 
				
			||||||
 | 
						fs, suffix := findMount(name)
 | 
				
			||||||
 | 
						if fs == nil {
 | 
				
			||||||
 | 
							return nil, &PathError{"open", name, ErrNotExist}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						handle, err := fs.OpenFile(suffix, flag, perm)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, &PathError{"open", name, err}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &File{name: name, handle: handle}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Open opens the file named for reading.
 | 
				
			||||||
 | 
					func Open(name string) (*File, error) {
 | 
				
			||||||
 | 
						return OpenFile(name, O_RDONLY, 0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Create creates the named file, overwriting it if it already exists.
 | 
				
			||||||
 | 
					func Create(name string) (*File, error) {
 | 
				
			||||||
 | 
						return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Read reads up to len(b) bytes from the File. It returns the number of bytes
 | 
				
			||||||
 | 
					// read and any error encountered. At end of file, Read returns 0, io.EOF.
 | 
				
			||||||
 | 
					func (f *File) Read(b []byte) (n int, err error) {
 | 
				
			||||||
 | 
						n, err = f.handle.Read(b)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							err = &PathError{"read", f.name, err}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Write writes len(b) bytes to the File. It returns the number of bytes written
 | 
				
			||||||
 | 
					// and an error, if any. Write returns a non-nil error when n != len(b).
 | 
				
			||||||
 | 
					func (f *File) Write(b []byte) (n int, err error) {
 | 
				
			||||||
 | 
						n, err = f.handle.Write(b)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							err = &PathError{"write", f.name, err}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Close closes the File, rendering it unusable for I/O.
 | 
				
			||||||
 | 
					func (f *File) Close() (err error) {
 | 
				
			||||||
 | 
						err = f.handle.Close()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							err = &PathError{"close", f.name, err}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Readdir is a stub, not yet implemented
 | 
					// Readdir is a stub, not yet implemented
 | 
				
			||||||
func (f *File) Readdir(n int) ([]FileInfo, error) {
 | 
					func (f *File) Readdir(n int) ([]FileInfo, error) {
 | 
				
			||||||
	return nil, notImplemented
 | 
						return nil, &PathError{"readdir", f.name, ErrNotImplemented}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Readdirnames is a stub, not yet implemented
 | 
					// Readdirnames is a stub, not yet implemented
 | 
				
			||||||
func (f *File) Readdirnames(n int) (names []string, err error) {
 | 
					func (f *File) Readdirnames(n int) (names []string, err error) {
 | 
				
			||||||
	return nil, notImplemented
 | 
						return nil, &PathError{"readdirnames", f.name, ErrNotImplemented}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Stat is a stub, not yet implemented
 | 
					// Stat is a stub, not yet implemented
 | 
				
			||||||
func (f *File) Stat() (FileInfo, error) {
 | 
					func (f *File) Stat() (FileInfo, error) {
 | 
				
			||||||
	return nil, notImplemented
 | 
						return nil, &PathError{"stat", f.name, ErrNotImplemented}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// NewFile returns a new File with the given file descriptor and name.
 | 
					 | 
				
			||||||
func NewFile(fd uintptr, name string) *File {
 | 
					 | 
				
			||||||
	return &File{fd, name}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Fd returns the integer Unix file descriptor referencing the open file. The
 | 
					 | 
				
			||||||
// file descriptor is valid only until f.Close is called.
 | 
					 | 
				
			||||||
func (f *File) Fd() uintptr {
 | 
					 | 
				
			||||||
	return f.fd
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
| 
						 | 
					@ -72,32 +142,8 @@ type PathError struct {
 | 
				
			||||||
	Err  error
 | 
						Err  error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
 | 
					func (e *PathError) Error() string {
 | 
				
			||||||
 | 
						return e.Op + " " + e.Path + ": " + e.Err.Error()
 | 
				
			||||||
// Open is a super simple stub function (for now), only capable of opening stdin, stdout, and stderr
 | 
					 | 
				
			||||||
func Open(name string) (*File, error) {
 | 
					 | 
				
			||||||
	fd := uintptr(999)
 | 
					 | 
				
			||||||
	switch name {
 | 
					 | 
				
			||||||
	case "/dev/stdin":
 | 
					 | 
				
			||||||
		fd = 0
 | 
					 | 
				
			||||||
	case "/dev/stdout":
 | 
					 | 
				
			||||||
		fd = 1
 | 
					 | 
				
			||||||
	case "/dev/stderr":
 | 
					 | 
				
			||||||
		fd = 2
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return nil, &PathError{"open", name, notImplemented}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return &File{fd, name}, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// OpenFile is a stub, passing through to the stub Open() call
 | 
					 | 
				
			||||||
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
 | 
					 | 
				
			||||||
	return Open(name)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Create is a stub, passing through to the stub Open() call
 | 
					 | 
				
			||||||
func Create(name string) (*File, error) {
 | 
					 | 
				
			||||||
	return Open(name)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type FileMode uint32
 | 
					type FileMode uint32
 | 
				
			||||||
| 
						 | 
					@ -155,12 +201,12 @@ type FileInfo interface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Stat is a stub, not yet implemented
 | 
					// Stat is a stub, not yet implemented
 | 
				
			||||||
func Stat(name string) (FileInfo, error) {
 | 
					func Stat(name string) (FileInfo, error) {
 | 
				
			||||||
	return nil, notImplemented
 | 
						return nil, &PathError{"stat", name, ErrNotImplemented}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Lstat is a stub, not yet implemented
 | 
					// Lstat is a stub, not yet implemented
 | 
				
			||||||
func Lstat(name string) (FileInfo, error) {
 | 
					func Lstat(name string) (FileInfo, error) {
 | 
				
			||||||
	return nil, notImplemented
 | 
						return nil, &PathError{"lstat", name, ErrNotImplemented}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Getwd is a stub (for now), always returning an empty string
 | 
					// Getwd is a stub (for now), always returning an empty string
 | 
				
			||||||
| 
						 | 
					@ -178,11 +224,6 @@ func TempDir() string {
 | 
				
			||||||
	return "/tmp"
 | 
						return "/tmp"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Mkdir is a stub, not yet implemented
 | 
					 | 
				
			||||||
func Mkdir(name string, perm FileMode) error {
 | 
					 | 
				
			||||||
	return notImplemented
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsExist is a stub (for now), always returning false
 | 
					// IsExist is a stub (for now), always returning false
 | 
				
			||||||
func IsExist(err error) bool {
 | 
					func IsExist(err error) bool {
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,28 +6,44 @@ import (
 | 
				
			||||||
	_ "unsafe"
 | 
						_ "unsafe"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
 | 
				
			||||||
 | 
					// standard output, and standard error file descriptors.
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						Stdin  = &File{stdioFileHandle(0), "/dev/stdin"}
 | 
				
			||||||
 | 
						Stdout = &File{stdioFileHandle(1), "/dev/stdout"}
 | 
				
			||||||
 | 
						Stderr = &File{stdioFileHandle(2), "/dev/stderr"}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// isOS indicates whether we're running on a real operating system with
 | 
				
			||||||
 | 
					// filesystem support.
 | 
				
			||||||
 | 
					const isOS = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// stdioFileHandle represents one of stdin, stdout, or stderr depending on the
 | 
				
			||||||
 | 
					// number. It implements the FileHandle interface.
 | 
				
			||||||
 | 
					type stdioFileHandle uint8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Read is unsupported on this system.
 | 
					// Read is unsupported on this system.
 | 
				
			||||||
func (f *File) Read(b []byte) (n int, err error) {
 | 
					func (f stdioFileHandle) Read(b []byte) (n int, err error) {
 | 
				
			||||||
	return 0, errUnsupported
 | 
						return 0, ErrUnsupported
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Write writes len(b) bytes to the output. It returns the number of bytes
 | 
					// Write writes len(b) bytes to the output. It returns the number of bytes
 | 
				
			||||||
// written or an error if this file is not stdout or stderr.
 | 
					// written or an error if this file is not stdout or stderr.
 | 
				
			||||||
func (f *File) Write(b []byte) (n int, err error) {
 | 
					func (f stdioFileHandle) Write(b []byte) (n int, err error) {
 | 
				
			||||||
	switch f.fd {
 | 
						switch f {
 | 
				
			||||||
	case Stdout.fd, Stderr.fd:
 | 
						case 1, 2: // stdout, stderr
 | 
				
			||||||
		for _, c := range b {
 | 
							for _, c := range b {
 | 
				
			||||||
			putchar(c)
 | 
								putchar(c)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return len(b), nil
 | 
							return len(b), nil
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return 0, errUnsupported
 | 
							return 0, ErrUnsupported
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Close is unsupported on this system.
 | 
					// Close is unsupported on this system.
 | 
				
			||||||
func (f *File) Close() error {
 | 
					func (f stdioFileHandle) Close() error {
 | 
				
			||||||
	return errUnsupported
 | 
						return ErrUnsupported
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//go:linkname putchar runtime.putchar
 | 
					//go:linkname putchar runtime.putchar
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,19 +6,105 @@ import (
 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						// Mount the host filesystem at the root directory. This is what most
 | 
				
			||||||
 | 
						// programs will be expecting.
 | 
				
			||||||
 | 
						Mount("/", unixFilesystem{})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
 | 
				
			||||||
 | 
					// standard output, and standard error file descriptors.
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						Stdin  = &File{unixFileHandle(0), "/dev/stdin"}
 | 
				
			||||||
 | 
						Stdout = &File{unixFileHandle(1), "/dev/stdout"}
 | 
				
			||||||
 | 
						Stderr = &File{unixFileHandle(2), "/dev/stderr"}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// isOS indicates whether we're running on a real operating system with
 | 
				
			||||||
 | 
					// filesystem support.
 | 
				
			||||||
 | 
					const isOS = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// unixFilesystem is an empty handle for a Unix/Linux filesystem. All operations
 | 
				
			||||||
 | 
					// are relative to the current working directory.
 | 
				
			||||||
 | 
					type unixFilesystem struct {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs unixFilesystem) Mkdir(path string, perm FileMode) error {
 | 
				
			||||||
 | 
						return handleSyscallError(syscall.Mkdir(path, uint32(perm)))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs unixFilesystem) Remove(path string) error {
 | 
				
			||||||
 | 
						return handleSyscallError(syscall.Unlink(path))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs unixFilesystem) OpenFile(path string, flag int, perm FileMode) (FileHandle, error) {
 | 
				
			||||||
 | 
						// Map os package flags to syscall flags.
 | 
				
			||||||
 | 
						syscallFlag := 0
 | 
				
			||||||
 | 
						if flag&O_RDONLY != 0 {
 | 
				
			||||||
 | 
							syscallFlag |= syscall.O_RDONLY
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flag&O_WRONLY != 0 {
 | 
				
			||||||
 | 
							syscallFlag |= syscall.O_WRONLY
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flag&O_RDWR != 0 {
 | 
				
			||||||
 | 
							syscallFlag |= syscall.O_RDWR
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flag&O_APPEND != 0 {
 | 
				
			||||||
 | 
							syscallFlag |= syscall.O_APPEND
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flag&O_CREATE != 0 {
 | 
				
			||||||
 | 
							syscallFlag |= syscall.O_CREAT
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flag&O_EXCL != 0 {
 | 
				
			||||||
 | 
							syscallFlag |= syscall.O_EXCL
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flag&O_SYNC != 0 {
 | 
				
			||||||
 | 
							syscallFlag |= syscall.O_SYNC
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flag&O_TRUNC != 0 {
 | 
				
			||||||
 | 
							syscallFlag |= syscall.O_TRUNC
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fp, err := syscall.Open(path, syscallFlag, uint32(perm))
 | 
				
			||||||
 | 
						return unixFileHandle(fp), handleSyscallError(err)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// unixFileHandle is a Unix file pointer with associated methods that implement
 | 
				
			||||||
 | 
					// the FileHandle interface.
 | 
				
			||||||
 | 
					type unixFileHandle uintptr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Read reads up to len(b) bytes from the File. It returns the number of bytes
 | 
					// Read reads up to len(b) bytes from the File. It returns the number of bytes
 | 
				
			||||||
// read and any error encountered. At end of file, Read returns 0, io.EOF.
 | 
					// read and any error encountered. At end of file, Read returns 0, io.EOF.
 | 
				
			||||||
func (f *File) Read(b []byte) (n int, err error) {
 | 
					func (f unixFileHandle) Read(b []byte) (n int, err error) {
 | 
				
			||||||
	return syscall.Read(int(f.fd), b)
 | 
						n, err = syscall.Read(int(f), b)
 | 
				
			||||||
 | 
						err = handleSyscallError(err)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Write writes len(b) bytes to the File. It returns the number of bytes written
 | 
					// Write writes len(b) bytes to the File. It returns the number of bytes written
 | 
				
			||||||
// and an error, if any. Write returns a non-nil error when n != len(b).
 | 
					// and an error, if any. Write returns a non-nil error when n != len(b).
 | 
				
			||||||
func (f *File) Write(b []byte) (n int, err error) {
 | 
					func (f unixFileHandle) Write(b []byte) (n int, err error) {
 | 
				
			||||||
	return syscall.Write(int(f.fd), b)
 | 
						n, err = syscall.Write(int(f), b)
 | 
				
			||||||
 | 
						err = handleSyscallError(err)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Close closes the File, rendering it unusable for I/O.
 | 
					// Close closes the File, rendering it unusable for I/O.
 | 
				
			||||||
func (f *File) Close() error {
 | 
					func (f unixFileHandle) Close() error {
 | 
				
			||||||
	return syscall.Close(int(f.fd))
 | 
						return handleSyscallError(syscall.Close(int(f)))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// handleSyscallError converts syscall errors into regular os package errors.
 | 
				
			||||||
 | 
					// The err parameter must be either nil or of type syscall.Errno.
 | 
				
			||||||
 | 
					func handleSyscallError(err error) error {
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch err.(syscall.Errno) {
 | 
				
			||||||
 | 
						case syscall.EEXIST:
 | 
				
			||||||
 | 
							return ErrExist
 | 
				
			||||||
 | 
						case syscall.ENOENT:
 | 
				
			||||||
 | 
							return ErrNotExist
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										85
									
								
								src/os/filesystem.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										85
									
								
								src/os/filesystem.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,85 @@
 | 
				
			||||||
 | 
					package os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// mounts lists the mount points currently mounted in the filesystem provided by
 | 
				
			||||||
 | 
					// the os package. To resolve a path to a mount point, it is scanned from top to
 | 
				
			||||||
 | 
					// bottom looking for the first prefix match.
 | 
				
			||||||
 | 
					var mounts []mountPoint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type mountPoint struct {
 | 
				
			||||||
 | 
						// prefix is a filesystem prefix, that always starts and ends with a forward
 | 
				
			||||||
 | 
						// slash. To denote the root filesystem, use a single slash: "/".
 | 
				
			||||||
 | 
						// This allows fast checking whether a path lies within a mount point.
 | 
				
			||||||
 | 
						prefix string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// filesystem is the Filesystem implementation that is mounted at this mount
 | 
				
			||||||
 | 
						// point.
 | 
				
			||||||
 | 
						filesystem Filesystem
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Filesystem provides an interface for generic filesystem drivers mounted in
 | 
				
			||||||
 | 
					// the os package. The errors returned must be one of the os.Err* errors, or a
 | 
				
			||||||
 | 
					// custom error if one doesn't exist. It should not be a *PathError because
 | 
				
			||||||
 | 
					// errors will be wrapped with a *PathError by the filesystem abstraction.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// WARNING: this interface is not finalized and may change in a future version.
 | 
				
			||||||
 | 
					type Filesystem interface {
 | 
				
			||||||
 | 
						// OpenFile opens the named file.
 | 
				
			||||||
 | 
						OpenFile(name string, flag int, perm FileMode) (FileHandle, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Mkdir creates a new directoy with the specified permission (before
 | 
				
			||||||
 | 
						// umask). Some filesystems may not support directories or permissions.
 | 
				
			||||||
 | 
						Mkdir(name string, perm FileMode) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Remove removes the named file or (empty) directory.
 | 
				
			||||||
 | 
						Remove(name string) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FileHandle is an interface that should be implemented by filesystems
 | 
				
			||||||
 | 
					// implementing the Filesystem interface.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// WARNING: this interface is not finalized and may change in a future version.
 | 
				
			||||||
 | 
					type FileHandle interface {
 | 
				
			||||||
 | 
						// Read reads up to len(b) bytes from the file.
 | 
				
			||||||
 | 
						Read(b []byte) (n int, err error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Write writes up to len(b) bytes to the file.
 | 
				
			||||||
 | 
						Write(b []byte) (n int, err error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Close closes the file, making it unusable for further writes.
 | 
				
			||||||
 | 
						Close() (err error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// findMount returns the appropriate (mounted) filesystem to use for a given
 | 
				
			||||||
 | 
					// filename plus the path relative to that filesystem.
 | 
				
			||||||
 | 
					func findMount(path string) (Filesystem, string) {
 | 
				
			||||||
 | 
						for i := len(mounts) - 1; i >= 0; i-- {
 | 
				
			||||||
 | 
							mount := mounts[i]
 | 
				
			||||||
 | 
							if strings.HasPrefix(path, mount.prefix) {
 | 
				
			||||||
 | 
								return mount.filesystem, path[len(mount.prefix)-1:]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if isOS {
 | 
				
			||||||
 | 
							// Assume that the first entry in the mounts slice is the OS filesystem
 | 
				
			||||||
 | 
							// at the root of the directory tree. Use it as-is, to support relative
 | 
				
			||||||
 | 
							// paths.
 | 
				
			||||||
 | 
							return mounts[0].filesystem, path
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, path
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Mount mounts the given filesystem in the filesystem abstraction layer of the
 | 
				
			||||||
 | 
					// os package. It is not possible to unmount filesystems. Filesystems added
 | 
				
			||||||
 | 
					// later will override earlier filesystems.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The provided prefix must start and end with a forward slash. This is true for
 | 
				
			||||||
 | 
					// the root directory ("/") for example.
 | 
				
			||||||
 | 
					func Mount(prefix string, filesystem Filesystem) {
 | 
				
			||||||
 | 
						if prefix[0] != '/' || prefix[len(prefix)-1] != '/' {
 | 
				
			||||||
 | 
							panic("os.Mount: invalid prefix")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mounts = append(mounts, mountPoint{prefix, filesystem})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,7 @@
 | 
				
			||||||
package syscall
 | 
					package syscall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This file defines errno and constants to match the darwin libsystem ABI.
 | 
					// This file defines errno and constants to match the darwin libsystem ABI.
 | 
				
			||||||
// Values have been determined experimentally by compiling some C code on macOS
 | 
					// Values have been copied from src/syscall/zerrors_darwin_amd64.go.
 | 
				
			||||||
// with Clang and looking at the resulting LLVM IR.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This function returns the error location in the darwin ABI.
 | 
					// This function returns the error location in the darwin ABI.
 | 
				
			||||||
// Discovered by compiling the following code using Clang:
 | 
					// Discovered by compiling the following code using Clang:
 | 
				
			||||||
| 
						 | 
					@ -24,28 +23,34 @@ func getErrno() Errno {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	ENOENT      Errno = 2
 | 
						ENOENT      Errno = 0x2
 | 
				
			||||||
	EINTR       Errno = 4
 | 
						EEXIST      Errno = 0x11
 | 
				
			||||||
	EMFILE      Errno = 24
 | 
						EINTR       Errno = 0x4
 | 
				
			||||||
	EAGAIN      Errno = 35
 | 
						EMFILE      Errno = 0x18
 | 
				
			||||||
	ETIMEDOUT   Errno = 60
 | 
						EAGAIN      Errno = 0x23
 | 
				
			||||||
	ENOSYS      Errno = 78
 | 
						ETIMEDOUT   Errno = 0x3c
 | 
				
			||||||
 | 
						ENOSYS      Errno = 0x4e
 | 
				
			||||||
	EWOULDBLOCK Errno = EAGAIN
 | 
						EWOULDBLOCK Errno = EAGAIN
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Signal int
 | 
					type Signal int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	SIGCHLD Signal = 20
 | 
						SIGCHLD Signal = 0x14
 | 
				
			||||||
	SIGINT  Signal = 2
 | 
						SIGINT  Signal = 0x2
 | 
				
			||||||
	SIGKILL Signal = 9
 | 
						SIGKILL Signal = 0x9
 | 
				
			||||||
	SIGTRAP Signal = 5
 | 
						SIGTRAP Signal = 0x5
 | 
				
			||||||
	SIGQUIT Signal = 3
 | 
						SIGQUIT Signal = 0x3
 | 
				
			||||||
	SIGTERM Signal = 15
 | 
						SIGTERM Signal = 0xf
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	O_RDONLY = 0
 | 
						O_RDONLY = 0x0
 | 
				
			||||||
	O_WRONLY = 1
 | 
						O_WRONLY = 0x1
 | 
				
			||||||
	O_RDWR   = 2
 | 
						O_RDWR   = 0x2
 | 
				
			||||||
 | 
						O_APPEND = 0x8
 | 
				
			||||||
 | 
						O_SYNC   = 0x80
 | 
				
			||||||
 | 
						O_CREAT  = 0x200
 | 
				
			||||||
 | 
						O_TRUNC  = 0x400
 | 
				
			||||||
 | 
						O_EXCL   = 0x800
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,14 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 | 
				
			||||||
	return 0, ENOSYS // TODO
 | 
						return 0, ENOSYS // TODO
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Mkdir(path string, mode uint32) (err error) {
 | 
				
			||||||
 | 
						return ENOSYS // TODO
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Unlink(path string) (err error) {
 | 
				
			||||||
 | 
						return ENOSYS // TODO
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Kill(pid int, sig Signal) (err error) {
 | 
					func Kill(pid int, sig Signal) (err error) {
 | 
				
			||||||
	return ENOSYS // TODO
 | 
						return ENOSYS // TODO
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								testdata/stdlib.go
									
										
									
									
										предоставленный
									
									
								
							
							
						
						
									
										6
									
								
								testdata/stdlib.go
									
										
									
									
										предоставленный
									
									
								
							| 
						 | 
					@ -9,9 +9,9 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	// package os, fmt
 | 
						// package os, fmt
 | 
				
			||||||
	fmt.Println("stdin: ", os.Stdin.Fd())
 | 
						fmt.Println("stdin: ", os.Stdin.Name())
 | 
				
			||||||
	fmt.Println("stdout:", os.Stdout.Fd())
 | 
						fmt.Println("stdout:", os.Stdout.Name())
 | 
				
			||||||
	fmt.Println("stderr:", os.Stderr.Fd())
 | 
						fmt.Println("stderr:", os.Stderr.Name())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// package math/rand
 | 
						// package math/rand
 | 
				
			||||||
	fmt.Println("pseudorandom number:", rand.Int31())
 | 
						fmt.Println("pseudorandom number:", rand.Int31())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								testdata/stdlib.txt
									
										
									
									
										предоставленный
									
									
								
							
							
						
						
									
										6
									
								
								testdata/stdlib.txt
									
										
									
									
										предоставленный
									
									
								
							| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
stdin:  0
 | 
					stdin:  /dev/stdin
 | 
				
			||||||
stdout: 1
 | 
					stdout: /dev/stdout
 | 
				
			||||||
stderr: 2
 | 
					stderr: /dev/stderr
 | 
				
			||||||
pseudorandom number: 1298498081
 | 
					pseudorandom number: 1298498081
 | 
				
			||||||
strings.IndexByte: 2
 | 
					strings.IndexByte: 2
 | 
				
			||||||
strings.Replace: An-example-string
 | 
					strings.Replace: An-example-string
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче