1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qglobal.h>
5#include "qsystemerror_p.h"
6#include <errno.h>
7#if defined(Q_CC_MSVC)
8# include <crtdbg.h>
9#endif
10#ifdef Q_OS_WIN
11# include <qt_windows.h>
12# include <comdef.h>
13#endif
14#ifndef QT_BOOTSTRAPPED
15# include <qcoreapplication.h>
16#endif
17
18QT_BEGIN_NAMESPACE
19
20using namespace Qt::StringLiterals;
21
22#if !defined(Q_OS_WIN) && QT_CONFIG(thread) && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX) && \
23 defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L
24namespace {
25 // There are two incompatible versions of strerror_r:
26 // a) the XSI/POSIX.1 version, which returns an int,
27 // indicating success or not
28 // b) the GNU version, which returns a char*, which may or may not
29 // be the beginning of the buffer we used
30 // The GNU libc manpage for strerror_r says you should use the XSI
31 // version in portable code. However, it's impossible to do that if
32 // _GNU_SOURCE is defined so we use C++ overloading to decide what to do
33 // depending on the return type
34 [[maybe_unused]] static inline QString fromstrerror_helper(int, const QByteArray &buf)
35 {
36 return QString::fromLocal8Bit(buf);
37 }
38 [[maybe_unused]] static inline QString fromstrerror_helper(const char *str, const QByteArray &)
39 {
40 return QString::fromLocal8Bit(str);
41 }
42}
43#endif
44
45#ifdef Q_OS_WIN
46static QString windowsErrorString(int errorCode)
47{
48 QString ret;
49 wchar_t *string = nullptr;
50 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
51 NULL,
52 errorCode,
53 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
54 (LPWSTR)&string,
55 0,
56 NULL);
57 ret = QString::fromWCharArray(string);
58 LocalFree((HLOCAL)string);
59
60 if (ret.isEmpty() && errorCode == ERROR_MOD_NOT_FOUND)
61 ret = QString::fromLatin1("The specified module could not be found.");
62 if (ret.endsWith("\r\n"_L1))
63 ret.chop(2);
64 if (ret.isEmpty())
65 ret = QString::fromLatin1("Unknown error 0x%1.")
66 .arg(unsigned(errorCode), 8, 16, '0'_L1);
67 return ret;
68}
69#endif
70
71static QString standardLibraryErrorString(int errorCode)
72{
73 const char *s = nullptr;
74 QString ret;
75 switch (errorCode) {
76 case 0:
77 break;
78 case EACCES:
79 s = QT_TRANSLATE_NOOP("QIODevice", "Permission denied");
80 break;
81 case EMFILE:
82 s = QT_TRANSLATE_NOOP("QIODevice", "Too many open files");
83 break;
84 case ENOENT:
85 s = QT_TRANSLATE_NOOP("QIODevice", "No such file or directory");
86 break;
87 case ENOSPC:
88 s = QT_TRANSLATE_NOOP("QIODevice", "No space left on device");
89 break;
90 default: {
91 #if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX)
92 QByteArray buf(1024, Qt::Uninitialized);
93 ret = fromstrerror_helper(strerror_r(errorCode, buf.data(), buf.size()), buf);
94 #else
95 ret = QString::fromLocal8Bit(ba: strerror(errnum: errorCode));
96 #endif
97 break; }
98 }
99 if (s) {
100#ifndef QT_BOOTSTRAPPED
101 ret = QCoreApplication::translate(context: "QIODevice", key: s);
102#else
103 ret = QString::fromLatin1(s);
104#endif
105 }
106 return ret.trimmed();
107}
108
109QString QSystemError::string(ErrorScope errorScope, int errorCode)
110{
111 switch (errorScope) {
112 case NativeError:
113#if defined(Q_OS_WIN)
114 return windowsErrorString(errorCode);
115#endif // else unix: native and standard library are the same
116 case StandardLibraryError:
117 return standardLibraryErrorString(errorCode);
118 default:
119 qWarning(msg: "invalid error scope");
120 Q_FALLTHROUGH();
121 case NoError:
122 return u"No error"_s;
123 }
124}
125
126QString QSystemError::stdString(int errorCode)
127{
128 return standardLibraryErrorString(errorCode: errorCode == -1 ? errno : errorCode);
129}
130
131#ifdef Q_OS_WIN
132QString QSystemError::windowsString(int errorCode)
133{
134 return windowsErrorString(errorCode == -1 ? GetLastError() : errorCode);
135}
136
137QString QSystemError::windowsComString(HRESULT hr)
138{
139 const _com_error comError(hr);
140 QString result = "COM error 0x"_L1 + QString::number(ulong(hr), 16);
141 if (const wchar_t *msg = comError.ErrorMessage())
142 result += ": "_L1 + QString::fromWCharArray(msg);
143 return result;
144}
145
146QString qt_error_string(int code)
147{
148 return windowsErrorString(code == -1 ? GetLastError() : code);
149}
150#else
151QString qt_error_string(int code)
152{
153 return standardLibraryErrorString(errorCode: code == -1 ? errno : code);
154}
155#endif
156
157QT_END_NAMESPACE
158

source code of qtbase/src/corelib/kernel/qsystemerror.cpp