gvisor/pkg/syserror/syserror.go

153 lines
5.2 KiB
Go

// Copyright 2018 Google LLC
//
// 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 syserror contains syscall error codes exported as error interface
// instead of Errno. This allows for fast comparison and returns when the
// comparand or return value is of type error because there is no need to
// convert from Errno to an interface, i.e., runtime.convT2I isn't called.
package syserror
import (
"errors"
"syscall"
)
// The following variables have the same meaning as their syscall equivalent.
var (
E2BIG = error(syscall.E2BIG)
EACCES = error(syscall.EACCES)
EAGAIN = error(syscall.EAGAIN)
EBADF = error(syscall.EBADF)
EBUSY = error(syscall.EBUSY)
ECHILD = error(syscall.ECHILD)
ECONNREFUSED = error(syscall.ECONNREFUSED)
ECONNRESET = error(syscall.ECONNRESET)
EEXIST = error(syscall.EEXIST)
EFAULT = error(syscall.EFAULT)
EFBIG = error(syscall.EFBIG)
EIDRM = error(syscall.EIDRM)
EINTR = error(syscall.EINTR)
EINVAL = error(syscall.EINVAL)
EIO = error(syscall.EIO)
EISDIR = error(syscall.EISDIR)
ELIBBAD = error(syscall.ELIBBAD)
ELOOP = error(syscall.ELOOP)
EMFILE = error(syscall.EMFILE)
EMSGSIZE = error(syscall.EMSGSIZE)
ENAMETOOLONG = error(syscall.ENAMETOOLONG)
ENOATTR = ENODATA
ENODATA = error(syscall.ENODATA)
ENODEV = error(syscall.ENODEV)
ENOENT = error(syscall.ENOENT)
ENOEXEC = error(syscall.ENOEXEC)
ENOLCK = error(syscall.ENOLCK)
ENOLINK = error(syscall.ENOLINK)
ENOMEM = error(syscall.ENOMEM)
ENOSPC = error(syscall.ENOSPC)
ENOSYS = error(syscall.ENOSYS)
ENOTDIR = error(syscall.ENOTDIR)
ENOTEMPTY = error(syscall.ENOTEMPTY)
ENOTSUP = error(syscall.ENOTSUP)
ENOTTY = error(syscall.ENOTTY)
ENXIO = error(syscall.ENXIO)
EOPNOTSUPP = error(syscall.EOPNOTSUPP)
EOVERFLOW = error(syscall.EOVERFLOW)
EPERM = error(syscall.EPERM)
EPIPE = error(syscall.EPIPE)
ERANGE = error(syscall.ERANGE)
EROFS = error(syscall.EROFS)
ESPIPE = error(syscall.ESPIPE)
ESRCH = error(syscall.ESRCH)
ETIMEDOUT = error(syscall.ETIMEDOUT)
EUSERS = error(syscall.EUSERS)
EWOULDBLOCK = error(syscall.EWOULDBLOCK)
EXDEV = error(syscall.EXDEV)
)
var (
// ErrWouldBlock is an internal error used to indicate that an operation
// cannot be satisfied immediately, and should be retried at a later
// time, possibly when the caller has received a notification that the
// operation may be able to complete. It is used by implementations of
// the kio.File interface.
ErrWouldBlock = errors.New("request would block")
// ErrInterrupted is returned if a request is interrupted before it can
// complete.
ErrInterrupted = errors.New("request was interrupted")
// ErrExceedsFileSizeLimit is returned if a request would exceed the
// file's size limit.
ErrExceedsFileSizeLimit = errors.New("exceeds file size limit")
)
// errorMap is the map used to convert generic errors into errnos.
var errorMap = map[error]syscall.Errno{}
// errorUnwrappers is an array of unwrap functions to extract typed errors.
var errorUnwrappers = []func(error) (syscall.Errno, bool){}
// AddErrorTranslation allows modules to populate the error map by adding their
// own translations during initialization. Returns if the error translation is
// accepted or not. A pre-existing translation will not be overwritten by the
// new translation.
func AddErrorTranslation(from error, to syscall.Errno) bool {
if _, ok := errorMap[from]; ok {
return false
}
errorMap[from] = to
return true
}
// AddErrorUnwrapper registers an unwrap method that can extract a concrete error
// from a typed, but not initialized, error.
func AddErrorUnwrapper(unwrap func(e error) (syscall.Errno, bool)) {
errorUnwrappers = append(errorUnwrappers, unwrap)
}
// TranslateError translates errors to errnos, it will return false if
// the error was not registered.
func TranslateError(from error) (syscall.Errno, bool) {
err, ok := errorMap[from]
if ok {
return err, ok
}
// Try to unwrap the error if we couldn't match an error
// exactly. This might mean that a package has its own
// error type.
for _, unwrap := range errorUnwrappers {
err, ok := unwrap(from)
if ok {
return err, ok
}
}
return 0, false
}
// ConvertIntr converts the provided error code (err) to another one (intr) if
// the first error corresponds to an interrupted operation.
func ConvertIntr(err, intr error) error {
if err == ErrInterrupted {
return intr
}
return err
}
func init() {
AddErrorTranslation(ErrWouldBlock, syscall.EWOULDBLOCK)
AddErrorTranslation(ErrInterrupted, syscall.EINTR)
AddErrorTranslation(ErrExceedsFileSizeLimit, syscall.EFBIG)
}