// ***************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * // * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * // ***************************************************************************** #include "sys_error.h" #include using namespace zen; namespace { std::wstring formatSystemErrorCode(ErrorCode ec) { switch (ec) //pretty much all codes currently used on CentOS 7 and macOS 10.15 { ZEN_CHECK_CASE_FOR_CONSTANT(EPERM); ZEN_CHECK_CASE_FOR_CONSTANT(ENOENT); ZEN_CHECK_CASE_FOR_CONSTANT(ESRCH); ZEN_CHECK_CASE_FOR_CONSTANT(EINTR); ZEN_CHECK_CASE_FOR_CONSTANT(EIO); ZEN_CHECK_CASE_FOR_CONSTANT(ENXIO); ZEN_CHECK_CASE_FOR_CONSTANT(E2BIG); ZEN_CHECK_CASE_FOR_CONSTANT(ENOEXEC); ZEN_CHECK_CASE_FOR_CONSTANT(EBADF); ZEN_CHECK_CASE_FOR_CONSTANT(ECHILD); ZEN_CHECK_CASE_FOR_CONSTANT(EAGAIN); ZEN_CHECK_CASE_FOR_CONSTANT(ENOMEM); ZEN_CHECK_CASE_FOR_CONSTANT(EACCES); ZEN_CHECK_CASE_FOR_CONSTANT(EFAULT); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTBLK); ZEN_CHECK_CASE_FOR_CONSTANT(EBUSY); ZEN_CHECK_CASE_FOR_CONSTANT(EEXIST); ZEN_CHECK_CASE_FOR_CONSTANT(EXDEV); ZEN_CHECK_CASE_FOR_CONSTANT(ENODEV); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTDIR); ZEN_CHECK_CASE_FOR_CONSTANT(EISDIR); ZEN_CHECK_CASE_FOR_CONSTANT(EINVAL); ZEN_CHECK_CASE_FOR_CONSTANT(ENFILE); ZEN_CHECK_CASE_FOR_CONSTANT(EMFILE); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTTY); ZEN_CHECK_CASE_FOR_CONSTANT(ETXTBSY); ZEN_CHECK_CASE_FOR_CONSTANT(EFBIG); ZEN_CHECK_CASE_FOR_CONSTANT(ENOSPC); ZEN_CHECK_CASE_FOR_CONSTANT(ESPIPE); ZEN_CHECK_CASE_FOR_CONSTANT(EROFS); ZEN_CHECK_CASE_FOR_CONSTANT(EMLINK); ZEN_CHECK_CASE_FOR_CONSTANT(EPIPE); ZEN_CHECK_CASE_FOR_CONSTANT(EDOM); ZEN_CHECK_CASE_FOR_CONSTANT(ERANGE); ZEN_CHECK_CASE_FOR_CONSTANT(EDEADLK); ZEN_CHECK_CASE_FOR_CONSTANT(ENAMETOOLONG); ZEN_CHECK_CASE_FOR_CONSTANT(ENOLCK); ZEN_CHECK_CASE_FOR_CONSTANT(ENOSYS); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTEMPTY); ZEN_CHECK_CASE_FOR_CONSTANT(ELOOP); ZEN_CHECK_CASE_FOR_CONSTANT(ENOMSG); ZEN_CHECK_CASE_FOR_CONSTANT(EIDRM); ZEN_CHECK_CASE_FOR_CONSTANT(ENOSTR); ZEN_CHECK_CASE_FOR_CONSTANT(ENODATA); ZEN_CHECK_CASE_FOR_CONSTANT(ETIME); ZEN_CHECK_CASE_FOR_CONSTANT(ENOSR); ZEN_CHECK_CASE_FOR_CONSTANT(EREMOTE); ZEN_CHECK_CASE_FOR_CONSTANT(ENOLINK); ZEN_CHECK_CASE_FOR_CONSTANT(EPROTO); ZEN_CHECK_CASE_FOR_CONSTANT(EMULTIHOP); ZEN_CHECK_CASE_FOR_CONSTANT(EBADMSG); ZEN_CHECK_CASE_FOR_CONSTANT(EOVERFLOW); ZEN_CHECK_CASE_FOR_CONSTANT(EILSEQ); ZEN_CHECK_CASE_FOR_CONSTANT(EUSERS); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTSOCK); ZEN_CHECK_CASE_FOR_CONSTANT(EDESTADDRREQ); ZEN_CHECK_CASE_FOR_CONSTANT(EMSGSIZE); ZEN_CHECK_CASE_FOR_CONSTANT(EPROTOTYPE); ZEN_CHECK_CASE_FOR_CONSTANT(ENOPROTOOPT); ZEN_CHECK_CASE_FOR_CONSTANT(EPROTONOSUPPORT); ZEN_CHECK_CASE_FOR_CONSTANT(ESOCKTNOSUPPORT); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTSUP); ZEN_CHECK_CASE_FOR_CONSTANT(EPFNOSUPPORT); ZEN_CHECK_CASE_FOR_CONSTANT(EAFNOSUPPORT); ZEN_CHECK_CASE_FOR_CONSTANT(EADDRINUSE); ZEN_CHECK_CASE_FOR_CONSTANT(EADDRNOTAVAIL); ZEN_CHECK_CASE_FOR_CONSTANT(ENETDOWN); ZEN_CHECK_CASE_FOR_CONSTANT(ENETUNREACH); ZEN_CHECK_CASE_FOR_CONSTANT(ENETRESET); ZEN_CHECK_CASE_FOR_CONSTANT(ECONNABORTED); ZEN_CHECK_CASE_FOR_CONSTANT(ECONNRESET); ZEN_CHECK_CASE_FOR_CONSTANT(ENOBUFS); ZEN_CHECK_CASE_FOR_CONSTANT(EISCONN); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTCONN); ZEN_CHECK_CASE_FOR_CONSTANT(ESHUTDOWN); ZEN_CHECK_CASE_FOR_CONSTANT(ETOOMANYREFS); ZEN_CHECK_CASE_FOR_CONSTANT(ETIMEDOUT); ZEN_CHECK_CASE_FOR_CONSTANT(ECONNREFUSED); ZEN_CHECK_CASE_FOR_CONSTANT(EHOSTDOWN); ZEN_CHECK_CASE_FOR_CONSTANT(EHOSTUNREACH); ZEN_CHECK_CASE_FOR_CONSTANT(EALREADY); ZEN_CHECK_CASE_FOR_CONSTANT(EINPROGRESS); ZEN_CHECK_CASE_FOR_CONSTANT(ESTALE); ZEN_CHECK_CASE_FOR_CONSTANT(EDQUOT); ZEN_CHECK_CASE_FOR_CONSTANT(ECANCELED); ZEN_CHECK_CASE_FOR_CONSTANT(EOWNERDEAD); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTRECOVERABLE); ZEN_CHECK_CASE_FOR_CONSTANT(ECHRNG); ZEN_CHECK_CASE_FOR_CONSTANT(EL2NSYNC); ZEN_CHECK_CASE_FOR_CONSTANT(EL3HLT); ZEN_CHECK_CASE_FOR_CONSTANT(EL3RST); ZEN_CHECK_CASE_FOR_CONSTANT(ELNRNG); ZEN_CHECK_CASE_FOR_CONSTANT(EUNATCH); ZEN_CHECK_CASE_FOR_CONSTANT(ENOCSI); ZEN_CHECK_CASE_FOR_CONSTANT(EL2HLT); ZEN_CHECK_CASE_FOR_CONSTANT(EBADE); ZEN_CHECK_CASE_FOR_CONSTANT(EBADR); ZEN_CHECK_CASE_FOR_CONSTANT(EXFULL); ZEN_CHECK_CASE_FOR_CONSTANT(ENOANO); ZEN_CHECK_CASE_FOR_CONSTANT(EBADRQC); ZEN_CHECK_CASE_FOR_CONSTANT(EBADSLT); ZEN_CHECK_CASE_FOR_CONSTANT(EBFONT); ZEN_CHECK_CASE_FOR_CONSTANT(ENONET); ZEN_CHECK_CASE_FOR_CONSTANT(ENOPKG); ZEN_CHECK_CASE_FOR_CONSTANT(EADV); ZEN_CHECK_CASE_FOR_CONSTANT(ESRMNT); ZEN_CHECK_CASE_FOR_CONSTANT(ECOMM); ZEN_CHECK_CASE_FOR_CONSTANT(EDOTDOT); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTUNIQ); ZEN_CHECK_CASE_FOR_CONSTANT(EBADFD); ZEN_CHECK_CASE_FOR_CONSTANT(EREMCHG); ZEN_CHECK_CASE_FOR_CONSTANT(ELIBACC); ZEN_CHECK_CASE_FOR_CONSTANT(ELIBBAD); ZEN_CHECK_CASE_FOR_CONSTANT(ELIBSCN); ZEN_CHECK_CASE_FOR_CONSTANT(ELIBMAX); ZEN_CHECK_CASE_FOR_CONSTANT(ELIBEXEC); ZEN_CHECK_CASE_FOR_CONSTANT(ERESTART); ZEN_CHECK_CASE_FOR_CONSTANT(ESTRPIPE); ZEN_CHECK_CASE_FOR_CONSTANT(EUCLEAN); ZEN_CHECK_CASE_FOR_CONSTANT(ENOTNAM); ZEN_CHECK_CASE_FOR_CONSTANT(ENAVAIL); ZEN_CHECK_CASE_FOR_CONSTANT(EISNAM); ZEN_CHECK_CASE_FOR_CONSTANT(EREMOTEIO); ZEN_CHECK_CASE_FOR_CONSTANT(ENOMEDIUM); ZEN_CHECK_CASE_FOR_CONSTANT(EMEDIUMTYPE); ZEN_CHECK_CASE_FOR_CONSTANT(ENOKEY); ZEN_CHECK_CASE_FOR_CONSTANT(EKEYEXPIRED); ZEN_CHECK_CASE_FOR_CONSTANT(EKEYREVOKED); ZEN_CHECK_CASE_FOR_CONSTANT(EKEYREJECTED); ZEN_CHECK_CASE_FOR_CONSTANT(ERFKILL); ZEN_CHECK_CASE_FOR_CONSTANT(EHWPOISON); default: return replaceCpy(_("Error code %x"), L"%x", numberTo(ec)); } } } std::wstring zen::formatGlibError(const std::string& functionName, GError* error) { if (!error) return formatSystemError(functionName, L"", _("Error description not available.") + L" null GError"); if (error->domain == G_FILE_ERROR) //"values corresponding to errno codes" return formatSystemError(functionName, error->code); std::wstring errorCode; if (error->domain == G_IO_ERROR) errorCode = [&]() -> std::wstring { switch (error->code) //GIOErrorEnum: https://gitlab.gnome.org/GNOME/glib/-/blob/master/gio/gioenums.h#L530 { ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_FAILED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_FOUND); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_EXISTS); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_IS_DIRECTORY); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_DIRECTORY); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_EMPTY); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_REGULAR_FILE); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_SYMBOLIC_LINK); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_MOUNTABLE_FILE); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_FILENAME_TOO_LONG); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_INVALID_FILENAME); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_TOO_MANY_LINKS); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NO_SPACE); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_INVALID_ARGUMENT); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_PERMISSION_DENIED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_SUPPORTED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_MOUNTED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_ALREADY_MOUNTED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_CLOSED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_CANCELLED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_PENDING); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_READ_ONLY); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_CANT_CREATE_BACKUP); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_WRONG_ETAG); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_TIMED_OUT); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_WOULD_RECURSE); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_BUSY); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_WOULD_BLOCK); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_HOST_NOT_FOUND); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_WOULD_MERGE); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_FAILED_HANDLED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_TOO_MANY_OPEN_FILES); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_INITIALIZED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_ADDRESS_IN_USE); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_PARTIAL_INPUT); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_INVALID_DATA); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_DBUS_ERROR); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_HOST_UNREACHABLE); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NETWORK_UNREACHABLE); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_CONNECTION_REFUSED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_PROXY_FAILED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_PROXY_AUTH_FAILED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_PROXY_NEED_AUTH); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_PROXY_NOT_ALLOWED); #ifndef GLIB_CHECK_VERSION //e.g Debian 8 (GLib 2.42) CentOS 7 (GLib 2.56) #error Where is GLib? #endif #if GLIB_CHECK_VERSION(2, 44, 0) static_assert(G_IO_ERROR_BROKEN_PIPE == G_IO_ERROR_CONNECTION_CLOSED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_CONNECTION_CLOSED); ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_NOT_CONNECTED); #endif #if GLIB_CHECK_VERSION(2, 48, 0) ZEN_CHECK_CASE_FOR_CONSTANT(G_IO_ERROR_MESSAGE_TOO_LARGE); #endif default: return replaceCpy(L"GIO error %x", L"%x", numberTo(error->code)); } }(); else { //g-file-error-quark => g-file-error //g-io-error-quark => g-io-error std::wstring domain = utfTo(::g_quark_to_string(error->domain)); //e.g. "g-io-error-quark" if (endsWith(domain, L"-quark")) domain = beforeLast(domain, L"-", IfNotFoundReturn::none); errorCode = domain + L' ' + numberTo(error->code); //e.g. "g-io-error 15" } const std::wstring errorMsg = utfTo(error->message); //e.g. "Unable to find or create trash directory for file.txt" return formatSystemError(functionName, errorCode, errorMsg); } std::wstring zen::getSystemErrorDescription(ErrorCode ec) //return empty string on error { const ErrorCode currentError = getLastError(); //not necessarily == ec ZEN_ON_SCOPE_EXIT(errno = currentError); std::wstring errorMsg; errorMsg = utfTo(::g_strerror(ec)); //... vs strerror(): "marginally improves thread safety, and marginally improves consistency" return trimCpy(errorMsg); //Windows messages seem to end with a space... } std::wstring zen::formatSystemError(const std::string& functionName, ErrorCode ec) { return formatSystemError(functionName, formatSystemErrorCode(ec), getSystemErrorDescription(ec)); } std::wstring zen::formatSystemError(const std::string& functionName, const std::wstring& errorCode, const std::wstring& errorMsg) { std::wstring output = trimCpy(errorCode); const std::wstring errorMsgFmt = trimCpy(errorMsg); if (!output.empty() && !errorMsgFmt.empty()) output += L": "; output += errorMsgFmt; if (!functionName.empty()) output += L" [" + utfTo(functionName) + L']'; return trimCpy(output); }