/* * The MIT License * * Copyright (C) 2016-2018 Alexander Saprykin * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * 'Software'), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "perror.h" #include "pmem.h" #include "pstring.h" #include "perror-private.h" #ifndef P_OS_WIN # if defined (P_OS_OS2) # define INCL_DOSERRORS # include # include # endif # include #endif struct PError_ { pint code; pint native_code; pchar *message; }; PErrorIO p_error_get_io_from_system (pint err_code) { switch (err_code) { case 0: return P_ERROR_IO_NONE; #if defined (P_OS_WIN) # ifdef WSAEADDRINUSE case WSAEADDRINUSE: return P_ERROR_IO_ADDRESS_IN_USE; # endif # ifdef WSAEWOULDBLOCK case WSAEWOULDBLOCK: return P_ERROR_IO_WOULD_BLOCK; # endif # ifdef WSAEACCES case WSAEACCES: return P_ERROR_IO_ACCESS_DENIED; # endif # ifdef WSA_INVALID_HANDLE case WSA_INVALID_HANDLE: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef WSA_INVALID_PARAMETER case WSA_INVALID_PARAMETER: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef WSAEBADF case WSAEBADF: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef WSAENOTSOCK case WSAENOTSOCK: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef WSAEINVAL case WSAEINVAL: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef WSAESOCKTNOSUPPORT case WSAESOCKTNOSUPPORT: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef WSAEOPNOTSUPP case WSAEOPNOTSUPP: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef WSAEPFNOSUPPORT case WSAEPFNOSUPPORT: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef WSAEAFNOSUPPORT case WSAEAFNOSUPPORT: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef WSAEPROTONOSUPPORT case WSAEPROTONOSUPPORT: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef WSAECANCELLED case WSAECANCELLED: return P_ERROR_IO_ABORTED; # endif # ifdef ERROR_ALREADY_EXISTS case ERROR_ALREADY_EXISTS: return P_ERROR_IO_EXISTS; # endif # ifdef ERROR_FILE_NOT_FOUND case ERROR_FILE_NOT_FOUND: return P_ERROR_IO_NOT_EXISTS; # endif # ifdef ERROR_NO_MORE_FILES case ERROR_NO_MORE_FILES: return P_ERROR_IO_NO_MORE; # endif # ifdef ERROR_ACCESS_DENIED case ERROR_ACCESS_DENIED: return P_ERROR_IO_ACCESS_DENIED; # endif # ifdef ERROR_OUTOFMEMORY case ERROR_OUTOFMEMORY: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef ERROR_NOT_ENOUGH_MEMORY case ERROR_NOT_ENOUGH_MEMORY: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef ERROR_INVALID_HANDLE # if !defined(WSA_INVALID_HANDLE) || (ERROR_INVALID_HANDLE != WSA_INVALID_HANDLE) case ERROR_INVALID_HANDLE: return P_ERROR_IO_INVALID_ARGUMENT; # endif # endif # ifdef ERROR_INVALID_PARAMETER # if !defined(WSA_INVALID_PARAMETER) || (ERROR_INVALID_PARAMETER != WSA_INVALID_PARAMETER) case ERROR_INVALID_PARAMETER: return P_ERROR_IO_INVALID_ARGUMENT; # endif # endif # ifdef ERROR_NOT_SUPPORTED case ERROR_NOT_SUPPORTED: return P_ERROR_IO_NOT_SUPPORTED; # endif #elif defined (P_OS_OS2) # ifdef ERROR_FILE_NOT_FOUND case ERROR_FILE_NOT_FOUND: return P_ERROR_IO_NOT_EXISTS; # endif # ifdef ERROR_PATH_NOT_FOUND case ERROR_PATH_NOT_FOUND: return P_ERROR_IO_NOT_EXISTS; # endif # ifdef ERROR_TOO_MANY_OPEN_FILES case ERROR_TOO_MANY_OPEN_FILES: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef ERROR_NOT_ENOUGH_MEMORY case ERROR_NOT_ENOUGH_MEMORY: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef ERROR_ACCESS_DENIED case ERROR_ACCESS_DENIED: return P_ERROR_IO_ACCESS_DENIED; # endif # ifdef ERROR_INVALID_HANDLE case ERROR_INVALID_HANDLE: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef ERROR_INVALID_PARAMETER case ERROR_INVALID_PARAMETER: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef ERROR_INVALID_ADDRESS case ERROR_INVALID_ADDRESS: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef ERROR_NO_MORE_FILES case ERROR_NO_MORE_FILES: return P_ERROR_IO_NO_MORE; # endif # ifdef ERROR_NOT_SUPPORTED case ERROR_NOT_SUPPORTED: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef ERROR_FILE_EXISTS case ERROR_FILE_EXISTS: return P_ERROR_IO_EXISTS; # endif #else /* !P_OS_WIN && !P_OS_OS2 */ # ifdef EACCES case EACCES: return P_ERROR_IO_ACCESS_DENIED; # endif # ifdef EPERM case EPERM: return P_ERROR_IO_ACCESS_DENIED; # endif # ifdef ENOMEM case ENOMEM: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef ENOSR case ENOSR: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef ENOBUFS case ENOBUFS: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef ENFILE case ENFILE: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef ENOSPC case ENOSPC: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef EMFILE case EMFILE: return P_ERROR_IO_NO_RESOURCES; # endif # ifdef EINVAL case EINVAL: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef EBADF case EBADF: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef ENOTSOCK case ENOTSOCK: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef EFAULT case EFAULT: return P_ERROR_IO_INVALID_ARGUMENT; # endif # ifdef EPROTOTYPE case EPROTOTYPE: return P_ERROR_IO_INVALID_ARGUMENT; # endif /* On Linux these errors can have same codes */ # if defined(ENOTSUP) && (!defined(EOPNOTSUPP) || ENOTSUP != EOPNOTSUPP) case ENOTSUP: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef ENOPROTOOPT case ENOPROTOOPT: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef EPROTONOSUPPORT case EPROTONOSUPPORT: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef EAFNOSUPPORT case EAFNOSUPPORT: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef EOPNOTSUPP case EOPNOTSUPP: return P_ERROR_IO_NOT_SUPPORTED; # endif # ifdef EADDRNOTAVAIL case EADDRNOTAVAIL: return P_ERROR_IO_NOT_AVAILABLE; # endif # ifdef ENETUNREACH case ENETUNREACH: return P_ERROR_IO_NOT_AVAILABLE; # endif # ifdef ENETDOWN case ENETDOWN: return P_ERROR_IO_NOT_AVAILABLE; # endif # ifdef EHOSTDOWN case EHOSTDOWN: return P_ERROR_IO_NOT_AVAILABLE; # endif # ifdef ENONET case ENONET: return P_ERROR_IO_NOT_AVAILABLE; # endif # ifdef EHOSTUNREACH case EHOSTUNREACH: return P_ERROR_IO_NOT_AVAILABLE; # endif # ifdef EINPROGRESS case EINPROGRESS: return P_ERROR_IO_IN_PROGRESS; # endif # ifdef EALREADY case EALREADY: return P_ERROR_IO_IN_PROGRESS; # endif # ifdef EISCONN case EISCONN: return P_ERROR_IO_CONNECTED; # endif # ifdef ECONNREFUSED case ECONNREFUSED: return P_ERROR_IO_CONNECTION_REFUSED; # endif # ifdef ENOTCONN case ENOTCONN: return P_ERROR_IO_NOT_CONNECTED; # endif # ifdef ECONNABORTED case ECONNABORTED: return P_ERROR_IO_ABORTED; # endif # ifdef EADDRINUSE case EADDRINUSE: return P_ERROR_IO_ADDRESS_IN_USE; # endif # ifdef ETIMEDOUT case ETIMEDOUT: return P_ERROR_IO_TIMED_OUT; # endif # ifdef EDQUOT case EDQUOT: return P_ERROR_IO_QUOTA; # endif # ifdef EISDIR case EISDIR: return P_ERROR_IO_IS_DIRECTORY; # endif # ifdef ENOTDIR case ENOTDIR: return P_ERROR_IO_NOT_DIRECTORY; # endif # ifdef EEXIST case EEXIST: return P_ERROR_IO_EXISTS; # endif # ifdef ENOENT case ENOENT: return P_ERROR_IO_NOT_EXISTS; # endif # ifdef ENAMETOOLONG case ENAMETOOLONG: return P_ERROR_IO_NAMETOOLONG; # endif # ifdef ENOSYS case ENOSYS: return P_ERROR_IO_NOT_IMPLEMENTED; # endif /* Some magic to deal with EWOULDBLOCK and EAGAIN. * Apparently on HP-UX these are actually defined to different values, * but on Linux, for example, they are the same. */ # if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK == EAGAIN /* We have both and they are the same: only emit one case. */ case EAGAIN: return P_ERROR_IO_WOULD_BLOCK; # else /* Else: consider each of them separately. This handles both the * case of having only one and the case where they are different values. */ # ifdef EAGAIN case EAGAIN: return P_ERROR_IO_WOULD_BLOCK; # endif # ifdef EWOULDBLOCK case EWOULDBLOCK: return P_ERROR_IO_WOULD_BLOCK; # endif # endif #endif /* !P_OS_WIN */ default: return P_ERROR_IO_FAILED; } } PErrorIO p_error_get_last_io (void) { return p_error_get_io_from_system (p_error_get_last_system ()); } PErrorIPC p_error_get_ipc_from_system (pint err_code) { switch (err_code) { case 0: return P_ERROR_IPC_NONE; #ifdef P_OS_WIN # ifdef ERROR_ALREADY_EXISTS case ERROR_ALREADY_EXISTS: return P_ERROR_IPC_EXISTS; # endif # ifdef ERROR_SEM_OWNER_DIED case ERROR_SEM_OWNER_DIED: return P_ERROR_IPC_NOT_EXISTS; # endif # ifdef ERROR_SEM_NOT_FOUND case ERROR_SEM_NOT_FOUND: return P_ERROR_IPC_NOT_EXISTS; # endif # ifdef ERROR_SEM_USER_LIMIT case ERROR_SEM_USER_LIMIT: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_TOO_MANY_SEMAPHORES case ERROR_TOO_MANY_SEMAPHORES: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_ACCESS_DENIED case ERROR_ACCESS_DENIED: return P_ERROR_IPC_ACCESS; # endif # ifdef ERROR_EXCL_SEM_ALREADY_OWNED case ERROR_EXCL_SEM_ALREADY_OWNED: return P_ERROR_IPC_ACCESS; # endif # ifdef ERROR_TOO_MANY_SEM_REQUESTS case ERROR_TOO_MANY_SEM_REQUESTS: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_TOO_MANY_POSTS case ERROR_TOO_MANY_POSTS: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_OUTOFMEMORY case ERROR_OUTOFMEMORY: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_NOT_ENOUGH_MEMORY case ERROR_NOT_ENOUGH_MEMORY: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_INVALID_HANDLE case ERROR_INVALID_HANDLE: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef ERROR_INVALID_PARAMETER case ERROR_INVALID_PARAMETER: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef ERROR_NOT_SUPPORTED case ERROR_NOT_SUPPORTED: return P_ERROR_IPC_NOT_IMPLEMENTED; # endif #elif defined (P_OS_OS2) # ifdef ERROR_NOT_ENOUGH_MEMORY case ERROR_NOT_ENOUGH_MEMORY: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_INVALID_PARAMETER case ERROR_INVALID_PARAMETER: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef ERROR_INVALID_NAME case ERROR_INVALID_NAME: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef ERROR_INVALID_HANDLE case ERROR_INVALID_HANDLE: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef ERROR_FILE_NOT_FOUND case ERROR_FILE_NOT_FOUND: return P_ERROR_IPC_NOT_EXISTS; # endif # ifdef ERROR_INVALID_ADDRESS case ERROR_INVALID_ADDRESS: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef ERROR_GEN_FAILURE case ERROR_GEN_FAILURE: return P_ERROR_IPC_FAILED; # endif # ifdef ERROR_LOCKED case ERROR_LOCKED: return P_ERROR_IPC_ACCESS; # endif # ifdef ERROR_DUPLICATE_NAME case ERROR_DUPLICATE_NAME: return P_ERROR_IPC_EXISTS; # endif # ifdef ERROR_TOO_MANY_HANDLES case ERROR_TOO_MANY_HANDLES: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_TOO_MANY_OPENS case ERROR_TOO_MANY_OPENS: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_TOO_MANY_SEM_REQUESTS case ERROR_TOO_MANY_SEM_REQUESTS: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ERROR_SEM_OWNER_DIED case ERROR_SEM_OWNER_DIED: return P_ERROR_IPC_NOT_EXISTS; # endif # ifdef ERROR_NOT_OWNER case ERROR_NOT_OWNER: return P_ERROR_IPC_ACCESS; # endif # ifdef ERROR_SEM_NOT_FOUND case ERROR_SEM_NOT_FOUND: return P_ERROR_IPC_NOT_EXISTS; # endif #else /* !P_OS_WINDOWS && !P_OS_OS2 */ # ifdef EACCES case EACCES: return P_ERROR_IPC_ACCESS; # endif # ifdef EPERM case EPERM: return P_ERROR_IPC_ACCESS; # endif # ifdef EEXIST case EEXIST: return P_ERROR_IPC_EXISTS; # endif # ifdef E2BIG case E2BIG: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef EFAULT case EFAULT: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef EFBIG case EFBIG: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef EINVAL case EINVAL: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef ELOOP case ELOOP: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef ERANGE case ERANGE: return P_ERROR_IPC_INVALID_ARGUMENT; # endif # ifdef ENOMEM case ENOMEM: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef EMFILE case EMFILE: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ENFILE case ENFILE: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef ENOSPC case ENOSPC: return P_ERROR_IPC_NO_RESOURCES; # endif # ifdef EIDRM case EIDRM: return P_ERROR_IPC_NOT_EXISTS; # endif # ifdef ENOENT case ENOENT: return P_ERROR_IPC_NOT_EXISTS; # endif # ifdef EOVERFLOW case EOVERFLOW: return P_ERROR_IPC_OVERFLOW; # endif # ifdef ENOSYS case ENOSYS: return P_ERROR_IPC_NOT_IMPLEMENTED; # endif # ifdef EDEADLK case EDEADLK: return P_ERROR_IPC_DEADLOCK; # endif # ifdef ENAMETOOLONG case ENAMETOOLONG: return P_ERROR_IPC_NAMETOOLONG; # endif #endif /* !P_OS_WIN */ default: return P_ERROR_IPC_FAILED; } } PErrorIPC p_error_get_last_ipc (void) { return p_error_get_ipc_from_system (p_error_get_last_system ()); } P_LIB_API PError * p_error_new (void) { PError *ret; if (P_UNLIKELY ((ret = p_malloc0 (sizeof (PError))) == NULL)) return NULL; return ret; } P_LIB_API PError * p_error_new_literal (pint code, pint native_code, const pchar *message) { PError *ret; if (P_UNLIKELY ((ret = p_error_new ()) == NULL)) return NULL; ret->code = code; ret->native_code = native_code; ret->message = p_strdup (message); return ret; } P_LIB_API const pchar * p_error_get_message (PError *error) { if (P_UNLIKELY (error == NULL)) return NULL; return error->message; } P_LIB_API pint p_error_get_code (PError *error) { if (P_UNLIKELY (error == NULL)) return 0; return error->code; } P_LIB_API pint p_error_get_native_code (PError *error) { if (P_UNLIKELY (error == NULL)) return 0; return error->native_code; } P_LIB_API PErrorDomain p_error_get_domain (PError *error) { if (P_UNLIKELY (error == NULL)) return P_ERROR_DOMAIN_NONE; if (error->code >= (pint) P_ERROR_DOMAIN_IPC) return P_ERROR_DOMAIN_IPC; else if (error->code >= (pint) P_ERROR_DOMAIN_IO) return P_ERROR_DOMAIN_IO; else return P_ERROR_DOMAIN_NONE; } P_LIB_API PError * p_error_copy (PError *error) { PError *ret; if (P_UNLIKELY (error == NULL)) return NULL; if (P_UNLIKELY ((ret = p_error_new_literal (error->code, error->native_code, error->message)) == NULL)) return NULL; return ret; } P_LIB_API void p_error_set_error (PError *error, pint code, pint native_code, const pchar *message) { if (P_UNLIKELY (error == NULL)) return; if (error->message != NULL) p_free (error->message); error->code = code; error->native_code = native_code; error->message = p_strdup (message); } P_LIB_API void p_error_set_error_p (PError **error, pint code, pint native_code, const pchar *message) { if (error == NULL || *error != NULL) return; *error = p_error_new_literal (code, native_code, message); } P_LIB_API void p_error_set_code (PError *error, pint code) { if (P_UNLIKELY (error == NULL)) return; error->code = code; } P_LIB_API void p_error_set_native_code (PError *error, pint native_code) { if (P_UNLIKELY (error == NULL)) return; error->native_code = native_code; } P_LIB_API void p_error_set_message (PError *error, const pchar *message) { if (P_UNLIKELY (error == NULL)) return; if (error->message != NULL) p_free (error->message); error->message = p_strdup (message); } P_LIB_API void p_error_clear (PError *error) { if (P_UNLIKELY (error == NULL)) return; if (error->message != NULL) p_free (error->message); error->message = NULL; error->code = 0; error->native_code = 0; } P_LIB_API void p_error_free (PError *error) { if (P_UNLIKELY (error == NULL)) return; if (error->message != NULL) p_free (error->message); p_free (error); } P_LIB_API pint p_error_get_last_system (void) { #ifdef P_OS_WIN return (pint) GetLastError (); #else # ifdef P_OS_VMS pint error_code = errno; if (error_code == EVMSERR) return vaxc$errno; else return error_code; # else return errno; # endif #endif } P_LIB_API pint p_error_get_last_net (void) { #if defined (P_OS_WIN) return WSAGetLastError (); #elif defined (P_OS_OS2) return sock_errno (); #else return p_error_get_last_system (); #endif } P_LIB_API void p_error_set_last_system (pint code) { #ifdef P_OS_WIN SetLastError (code); #else errno = code; #endif } P_LIB_API void p_error_set_last_net (pint code) { #if defined (P_OS_WIN) WSASetLastError (code); #elif defined (P_OS_OS2) P_UNUSED (code); #else errno = code; #endif }