From 6fc4a3ed049bd71d72398929cb083a4c80076ea2 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Tue, 25 Jun 2024 16:02:54 +0800 Subject: [PATCH 1/2] patch os, syscall, io/fs: Errno, Stdin/out/err --- internal/lib/io/fs/fs.go | 10 ++ internal/lib/os/error.go | 144 +++++++++++++++++++ internal/lib/os/file.go | 6 +- internal/lib/os/os.go | 33 ----- internal/lib/os/types.go | 26 +++- internal/lib/syscall/errors.go | 16 +++ internal/lib/syscall/syscall_unix.go | 59 ++++++++ internal/lib/syscall/zerrors_darwin_arm64.go | 129 +++++++++++++++++ 8 files changed, 386 insertions(+), 37 deletions(-) create mode 100644 internal/lib/os/error.go create mode 100644 internal/lib/syscall/errors.go create mode 100644 internal/lib/syscall/syscall_unix.go create mode 100644 internal/lib/syscall/zerrors_darwin_arm64.go diff --git a/internal/lib/io/fs/fs.go b/internal/lib/io/fs/fs.go index faaf0ade..dd8b88c7 100644 --- a/internal/lib/io/fs/fs.go +++ b/internal/lib/io/fs/fs.go @@ -19,6 +19,16 @@ package fs // llgo:skipall import ( _ "unsafe" + + "github.com/goplus/llgo/internal/lib/syscall" +) + +var ( + ErrInvalid = syscall.ErrInvalid + ErrPermission = syscall.ErrPermission + ErrExist = syscall.ErrExist + ErrNotExist = syscall.ErrNotExist + ErrClosed = syscall.ErrClosed ) // ----------------------------------------------------------------------------- diff --git a/internal/lib/os/error.go b/internal/lib/os/error.go new file mode 100644 index 00000000..b8c1ee73 --- /dev/null +++ b/internal/lib/os/error.go @@ -0,0 +1,144 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "io/fs" + "syscall" +) + +// Portable analogs of some common system call errors. +// +// Errors returned from this package may be tested against these errors +// with errors.Is. +var ( + // ErrInvalid indicates an invalid argument. + // Methods on File will return this error when the receiver is nil. + ErrInvalid = fs.ErrInvalid // "invalid argument" + + ErrPermission = fs.ErrPermission // "permission denied" + ErrExist = fs.ErrExist // "file already exists" + ErrNotExist = fs.ErrNotExist // "file does not exist" + ErrClosed = fs.ErrClosed // "file already closed" + + // TODO(xsw): + // ErrNoDeadline = errNoDeadline() // "file type does not support deadline" + // ErrDeadlineExceeded = errDeadlineExceeded() // "i/o timeout" +) + +// func errNoDeadline() error { return poll.ErrNoDeadline } + +// errDeadlineExceeded returns the value for os.ErrDeadlineExceeded. +// This error comes from the internal/poll package, which is also +// used by package net. Doing it this way ensures that the net +// package will return os.ErrDeadlineExceeded for an exceeded deadline, +// as documented by net.Conn.SetDeadline, without requiring any extra +// work in the net package and without requiring the internal/poll +// package to import os (which it can't, because that would be circular). +// func errDeadlineExceeded() error { return poll.ErrDeadlineExceeded } + +type timeout interface { + Timeout() bool +} + +// PathError records an error and the operation and file path that caused it. +type PathError = fs.PathError + +// SyscallError records an error from a specific system call. +type SyscallError struct { + Syscall string + Err error +} + +func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() } + +func (e *SyscallError) Unwrap() error { return e.Err } + +// Timeout reports whether this error represents a timeout. +func (e *SyscallError) Timeout() bool { + t, ok := e.Err.(timeout) + return ok && t.Timeout() +} + +// NewSyscallError returns, as an error, a new SyscallError +// with the given system call name and error details. +// As a convenience, if err is nil, NewSyscallError returns nil. +func NewSyscallError(syscall string, err error) error { + if err == nil { + return nil + } + return &SyscallError{syscall, err} +} + +// IsExist returns a boolean indicating whether the error is known to report +// that a file or directory already exists. It is satisfied by ErrExist as +// well as some syscall errors. +// +// This function predates errors.Is. It only supports errors returned by +// the os package. New code should use errors.Is(err, fs.ErrExist). +func IsExist(err error) bool { + return underlyingErrorIs(err, ErrExist) +} + +// IsNotExist returns a boolean indicating whether the error is known to +// report that a file or directory does not exist. It is satisfied by +// ErrNotExist as well as some syscall errors. +// +// This function predates errors.Is. It only supports errors returned by +// the os package. New code should use errors.Is(err, fs.ErrNotExist). +func IsNotExist(err error) bool { + return underlyingErrorIs(err, ErrNotExist) +} + +// IsPermission returns a boolean indicating whether the error is known to +// report that permission is denied. It is satisfied by ErrPermission as well +// as some syscall errors. +// +// This function predates errors.Is. It only supports errors returned by +// the os package. New code should use errors.Is(err, fs.ErrPermission). +func IsPermission(err error) bool { + return underlyingErrorIs(err, ErrPermission) +} + +// IsTimeout returns a boolean indicating whether the error is known +// to report that a timeout occurred. +// +// This function predates errors.Is, and the notion of whether an +// error indicates a timeout can be ambiguous. For example, the Unix +// error EWOULDBLOCK sometimes indicates a timeout and sometimes does not. +// New code should use errors.Is with a value appropriate to the call +// returning the error, such as os.ErrDeadlineExceeded. +func IsTimeout(err error) bool { + terr, ok := underlyingError(err).(timeout) + return ok && terr.Timeout() +} + +type syscallErrorType = syscall.Errno + +func underlyingErrorIs(err, target error) bool { + // Note that this function is not errors.Is: + // underlyingError only unwraps the specific error-wrapping types + // that it historically did, not all errors implementing Unwrap(). + err = underlyingError(err) + if err == target { + return true + } + // To preserve prior behavior, only examine syscall errors. + e, ok := err.(syscallErrorType) + return ok && e.Is(target) +} + +// underlyingError returns the underlying error for known os error types. +func underlyingError(err error) error { + switch err := err.(type) { + case *PathError: + return err.Err + case *LinkError: + return err.Err + case *SyscallError: + return err.Err + } + return err +} diff --git a/internal/lib/os/file.go b/internal/lib/os/file.go index 89ed15b4..5f598635 100644 --- a/internal/lib/os/file.go +++ b/internal/lib/os/file.go @@ -4,10 +4,13 @@ package os +import ( + "syscall" +) + // Name returns the name of the file as presented to Open. func (f *File) Name() string { return f.name } -/* // Stdin, Stdout, and Stderr are open Files pointing to the standard input, // standard output, and standard error file descriptors. // @@ -44,6 +47,7 @@ const ( SEEK_END int = 2 // seek relative to the end ) +/* // Read reads up to len(b) bytes from the File and stores them in b. // It returns the number of bytes read and any error encountered. // At end of file, Read returns 0, io.EOF. diff --git a/internal/lib/os/os.go b/internal/lib/os/os.go index 87fe09cd..cf92254a 100644 --- a/internal/lib/os/os.go +++ b/internal/lib/os/os.go @@ -19,7 +19,6 @@ package os // llgo:skipall import ( "errors" - "io/fs" "runtime" _ "unsafe" @@ -31,38 +30,6 @@ const ( LLGoPackage = true ) -type timeout interface { - Timeout() bool -} - -type PathError = fs.PathError - -// SyscallError records an error from a specific system call. -type SyscallError struct { - Syscall string - Err error -} - -func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() } - -func (e *SyscallError) Unwrap() error { return e.Err } - -// Timeout reports whether this error represents a timeout. -func (e *SyscallError) Timeout() bool { - t, ok := e.Err.(timeout) - return ok && t.Timeout() -} - -// NewSyscallError returns, as an error, a new SyscallError -// with the given system call name and error details. -// As a convenience, if err is nil, NewSyscallError returns nil. -func NewSyscallError(syscall string, err error) error { - if err == nil { - return nil - } - return &SyscallError{syscall, err} -} - // LinkError records an error during a link or symlink or rename // system call and the paths that caused it. type LinkError struct { diff --git a/internal/lib/os/types.go b/internal/lib/os/types.go index 0e56d700..f9d74435 100644 --- a/internal/lib/os/types.go +++ b/internal/lib/os/types.go @@ -7,8 +7,6 @@ package os import ( "io/fs" "syscall" - - "github.com/goplus/llgo/c" ) // Getpagesize returns the underlying system's memory page size. @@ -16,10 +14,32 @@ func Getpagesize() int { return syscall.Getpagesize() } // File represents an open file descriptor. type File struct { - fd c.Int + fd uintptr name string } +// NewFile returns a new File with the given file descriptor and +// name. The returned value will be nil if fd is not a valid file +// descriptor. On Unix systems, if the file descriptor is in +// non-blocking mode, NewFile will attempt to return a pollable File +// (one for which the SetDeadline methods work). +// +// After passing it to NewFile, fd may become invalid under the same +// conditions described in the comments of the Fd method, and the same +// constraints apply. +func NewFile(fd uintptr, name string) *File { + return &File{fd, name} +} + +// checkValid checks whether f is valid for use. +// If not, it returns an appropriate error, perhaps incorporating the operation name op. +func (f *File) checkValid(op string) error { + if f == nil { + return ErrInvalid + } + return nil +} + // A FileInfo describes a file and is returned by Stat and Lstat. type FileInfo = fs.FileInfo diff --git a/internal/lib/syscall/errors.go b/internal/lib/syscall/errors.go new file mode 100644 index 00000000..e35f780d --- /dev/null +++ b/internal/lib/syscall/errors.go @@ -0,0 +1,16 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +import "errors" + +// from internal/oserror +var ( + ErrInvalid = errors.New("invalid argument") + ErrPermission = errors.New("permission denied") + ErrExist = errors.New("file already exists") + ErrNotExist = errors.New("file does not exist") + ErrClosed = errors.New("file already closed") +) diff --git a/internal/lib/syscall/syscall_unix.go b/internal/lib/syscall/syscall_unix.go new file mode 100644 index 00000000..95fe2f49 --- /dev/null +++ b/internal/lib/syscall/syscall_unix.go @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package syscall + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/internal/lib/errors" +) + +var ( + Stdin = 0 + Stdout = 1 + Stderr = 2 +) + +type Errno uintptr + +func (e Errno) Error() string { + ret := c.Strerror(c.Int(e)) + return unsafe.String((*byte)(unsafe.Pointer(ret)), c.Strlen(ret)) +} + +func (e Errno) Is(target error) bool { + switch target { + case ErrPermission: + return e == EACCES || e == EPERM + case ErrExist: + return e == EEXIST || e == ENOTEMPTY + case ErrNotExist: + return e == ENOENT + case errors.ErrUnsupported: + return e == ENOSYS || e == ENOTSUP || e == EOPNOTSUPP + } + return false +} + +func (e Errno) Temporary() bool { + return e == EINTR || e == EMFILE || e == ENFILE || e.Timeout() +} + +func (e Errno) Timeout() bool { + return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT +} diff --git a/internal/lib/syscall/zerrors_darwin_arm64.go b/internal/lib/syscall/zerrors_darwin_arm64.go new file mode 100644 index 00000000..b9906f0f --- /dev/null +++ b/internal/lib/syscall/zerrors_darwin_arm64.go @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package syscall + +// Errors +const ( + E2BIG = Errno(0x7) + EACCES = Errno(0xd) + EADDRINUSE = Errno(0x30) + EADDRNOTAVAIL = Errno(0x31) + EAFNOSUPPORT = Errno(0x2f) + EAGAIN = Errno(0x23) + EALREADY = Errno(0x25) + EAUTH = Errno(0x50) + EBADARCH = Errno(0x56) + EBADEXEC = Errno(0x55) + EBADF = Errno(0x9) + EBADMACHO = Errno(0x58) + EBADMSG = Errno(0x5e) + EBADRPC = Errno(0x48) + EBUSY = Errno(0x10) + ECANCELED = Errno(0x59) + ECHILD = Errno(0xa) + ECONNABORTED = Errno(0x35) + ECONNREFUSED = Errno(0x3d) + ECONNRESET = Errno(0x36) + EDEADLK = Errno(0xb) + EDESTADDRREQ = Errno(0x27) + EDEVERR = Errno(0x53) + EDOM = Errno(0x21) + EDQUOT = Errno(0x45) + EEXIST = Errno(0x11) + EFAULT = Errno(0xe) + EFBIG = Errno(0x1b) + EFTYPE = Errno(0x4f) + EHOSTDOWN = Errno(0x40) + EHOSTUNREACH = Errno(0x41) + EIDRM = Errno(0x5a) + EILSEQ = Errno(0x5c) + EINPROGRESS = Errno(0x24) + EINTR = Errno(0x4) + EINVAL = Errno(0x16) + EIO = Errno(0x5) + EISCONN = Errno(0x38) + EISDIR = Errno(0x15) + ELAST = Errno(0x6a) + ELOOP = Errno(0x3e) + EMFILE = Errno(0x18) + EMLINK = Errno(0x1f) + EMSGSIZE = Errno(0x28) + EMULTIHOP = Errno(0x5f) + ENAMETOOLONG = Errno(0x3f) + ENEEDAUTH = Errno(0x51) + ENETDOWN = Errno(0x32) + ENETRESET = Errno(0x34) + ENETUNREACH = Errno(0x33) + ENFILE = Errno(0x17) + ENOATTR = Errno(0x5d) + ENOBUFS = Errno(0x37) + ENODATA = Errno(0x60) + ENODEV = Errno(0x13) + ENOENT = Errno(0x2) + ENOEXEC = Errno(0x8) + ENOLCK = Errno(0x4d) + ENOLINK = Errno(0x61) + ENOMEM = Errno(0xc) + ENOMSG = Errno(0x5b) + ENOPOLICY = Errno(0x67) + ENOPROTOOPT = Errno(0x2a) + ENOSPC = Errno(0x1c) + ENOSR = Errno(0x62) + ENOSTR = Errno(0x63) + ENOSYS = Errno(0x4e) + ENOTBLK = Errno(0xf) + ENOTCONN = Errno(0x39) + ENOTDIR = Errno(0x14) + ENOTEMPTY = Errno(0x42) + ENOTRECOVERABLE = Errno(0x68) + ENOTSOCK = Errno(0x26) + ENOTSUP = Errno(0x2d) + ENOTTY = Errno(0x19) + ENXIO = Errno(0x6) + EOPNOTSUPP = Errno(0x66) + EOVERFLOW = Errno(0x54) + EOWNERDEAD = Errno(0x69) + EPERM = Errno(0x1) + EPFNOSUPPORT = Errno(0x2e) + EPIPE = Errno(0x20) + EPROCLIM = Errno(0x43) + EPROCUNAVAIL = Errno(0x4c) + EPROGMISMATCH = Errno(0x4b) + EPROGUNAVAIL = Errno(0x4a) + EPROTO = Errno(0x64) + EPROTONOSUPPORT = Errno(0x2b) + EPROTOTYPE = Errno(0x29) + EPWROFF = Errno(0x52) + EQFULL = Errno(0x6a) + ERANGE = Errno(0x22) + EREMOTE = Errno(0x47) + EROFS = Errno(0x1e) + ERPCMISMATCH = Errno(0x49) + ESHLIBVERS = Errno(0x57) + ESHUTDOWN = Errno(0x3a) + ESOCKTNOSUPPORT = Errno(0x2c) + ESPIPE = Errno(0x1d) + ESRCH = Errno(0x3) + ESTALE = Errno(0x46) + ETIME = Errno(0x65) + ETIMEDOUT = Errno(0x3c) + ETOOMANYREFS = Errno(0x3b) + ETXTBSY = Errno(0x1a) + EUSERS = Errno(0x44) + EWOULDBLOCK = Errno(0x23) + EXDEV = Errno(0x12) +) From 207c41581ce42ca8d4e26d8f2a6311a78a8ef4c2 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Tue, 25 Jun 2024 16:11:29 +0800 Subject: [PATCH 2/2] patch syscall: errors for linux --- ...rors_darwin_arm64.go => zerrors_darwin.go} | 0 internal/lib/syscall/zerrors_linux.go | 154 ++++++++++++++++++ 2 files changed, 154 insertions(+) rename internal/lib/syscall/{zerrors_darwin_arm64.go => zerrors_darwin.go} (100%) create mode 100644 internal/lib/syscall/zerrors_linux.go diff --git a/internal/lib/syscall/zerrors_darwin_arm64.go b/internal/lib/syscall/zerrors_darwin.go similarity index 100% rename from internal/lib/syscall/zerrors_darwin_arm64.go rename to internal/lib/syscall/zerrors_darwin.go diff --git a/internal/lib/syscall/zerrors_linux.go b/internal/lib/syscall/zerrors_linux.go new file mode 100644 index 00000000..5ecada1a --- /dev/null +++ b/internal/lib/syscall/zerrors_linux.go @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package syscall + +// Errors +const ( + E2BIG = Errno(0x7) + EACCES = Errno(0xd) + EADDRINUSE = Errno(0x62) + EADDRNOTAVAIL = Errno(0x63) + EADV = Errno(0x44) + EAFNOSUPPORT = Errno(0x61) + EAGAIN = Errno(0xb) + EALREADY = Errno(0x72) + EBADE = Errno(0x34) + EBADF = Errno(0x9) + EBADFD = Errno(0x4d) + EBADMSG = Errno(0x4a) + EBADR = Errno(0x35) + EBADRQC = Errno(0x38) + EBADSLT = Errno(0x39) + EBFONT = Errno(0x3b) + EBUSY = Errno(0x10) + ECANCELED = Errno(0x7d) + ECHILD = Errno(0xa) + ECHRNG = Errno(0x2c) + ECOMM = Errno(0x46) + ECONNABORTED = Errno(0x67) + ECONNREFUSED = Errno(0x6f) + ECONNRESET = Errno(0x68) + EDEADLK = Errno(0x23) + EDEADLOCK = Errno(0x23) + EDESTADDRREQ = Errno(0x59) + EDOM = Errno(0x21) + EDOTDOT = Errno(0x49) + EDQUOT = Errno(0x7a) + EEXIST = Errno(0x11) + EFAULT = Errno(0xe) + EFBIG = Errno(0x1b) + EHOSTDOWN = Errno(0x70) + EHOSTUNREACH = Errno(0x71) + EIDRM = Errno(0x2b) + EILSEQ = Errno(0x54) + EINPROGRESS = Errno(0x73) + EINTR = Errno(0x4) + EINVAL = Errno(0x16) + EIO = Errno(0x5) + EISCONN = Errno(0x6a) + EISDIR = Errno(0x15) + EISNAM = Errno(0x78) + EKEYEXPIRED = Errno(0x7f) + EKEYREJECTED = Errno(0x81) + EKEYREVOKED = Errno(0x80) + EL2HLT = Errno(0x33) + EL2NSYNC = Errno(0x2d) + EL3HLT = Errno(0x2e) + EL3RST = Errno(0x2f) + ELIBACC = Errno(0x4f) + ELIBBAD = Errno(0x50) + ELIBEXEC = Errno(0x53) + ELIBMAX = Errno(0x52) + ELIBSCN = Errno(0x51) + ELNRNG = Errno(0x30) + ELOOP = Errno(0x28) + EMEDIUMTYPE = Errno(0x7c) + EMFILE = Errno(0x18) + EMLINK = Errno(0x1f) + EMSGSIZE = Errno(0x5a) + EMULTIHOP = Errno(0x48) + ENAMETOOLONG = Errno(0x24) + ENAVAIL = Errno(0x77) + ENETDOWN = Errno(0x64) + ENETRESET = Errno(0x66) + ENETUNREACH = Errno(0x65) + ENFILE = Errno(0x17) + ENOANO = Errno(0x37) + ENOBUFS = Errno(0x69) + ENOCSI = Errno(0x32) + ENODATA = Errno(0x3d) + ENODEV = Errno(0x13) + ENOENT = Errno(0x2) + ENOEXEC = Errno(0x8) + ENOKEY = Errno(0x7e) + ENOLCK = Errno(0x25) + ENOLINK = Errno(0x43) + ENOMEDIUM = Errno(0x7b) + ENOMEM = Errno(0xc) + ENOMSG = Errno(0x2a) + ENONET = Errno(0x40) + ENOPKG = Errno(0x41) + ENOPROTOOPT = Errno(0x5c) + ENOSPC = Errno(0x1c) + ENOSR = Errno(0x3f) + ENOSTR = Errno(0x3c) + ENOSYS = Errno(0x26) + ENOTBLK = Errno(0xf) + ENOTCONN = Errno(0x6b) + ENOTDIR = Errno(0x14) + ENOTEMPTY = Errno(0x27) + ENOTNAM = Errno(0x76) + ENOTRECOVERABLE = Errno(0x83) + ENOTSOCK = Errno(0x58) + ENOTSUP = Errno(0x5f) + ENOTTY = Errno(0x19) + ENOTUNIQ = Errno(0x4c) + ENXIO = Errno(0x6) + EOPNOTSUPP = Errno(0x5f) + EOVERFLOW = Errno(0x4b) + EOWNERDEAD = Errno(0x82) + EPERM = Errno(0x1) + EPFNOSUPPORT = Errno(0x60) + EPIPE = Errno(0x20) + EPROTO = Errno(0x47) + EPROTONOSUPPORT = Errno(0x5d) + EPROTOTYPE = Errno(0x5b) + ERANGE = Errno(0x22) + EREMCHG = Errno(0x4e) + EREMOTE = Errno(0x42) + EREMOTEIO = Errno(0x79) + ERESTART = Errno(0x55) + ERFKILL = Errno(0x84) + EROFS = Errno(0x1e) + ESHUTDOWN = Errno(0x6c) + ESOCKTNOSUPPORT = Errno(0x5e) + ESPIPE = Errno(0x1d) + ESRCH = Errno(0x3) + ESRMNT = Errno(0x45) + ESTALE = Errno(0x74) + ESTRPIPE = Errno(0x56) + ETIME = Errno(0x3e) + ETIMEDOUT = Errno(0x6e) + ETOOMANYREFS = Errno(0x6d) + ETXTBSY = Errno(0x1a) + EUCLEAN = Errno(0x75) + EUNATCH = Errno(0x31) + EUSERS = Errno(0x57) + EWOULDBLOCK = Errno(0xb) + EXDEV = Errno(0x12) + EXFULL = Errno(0x36) +)