1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <qglobal.h>
41#include "qsystemerror_p.h"
42#include <errno.h>
43#if defined(Q_CC_MSVC)
44# include <crtdbg.h>
45#endif
46#ifdef Q_OS_WIN
47# include <qt_windows.h>
48#endif
49
50QT_BEGIN_NAMESPACE
51
52#if !defined(Q_OS_WIN) && QT_CONFIG(thread) && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX) && \
53 defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L
54namespace {
55 // There are two incompatible versions of strerror_r:
56 // a) the XSI/POSIX.1 version, which returns an int,
57 // indicating success or not
58 // b) the GNU version, which returns a char*, which may or may not
59 // be the beginning of the buffer we used
60 // The GNU libc manpage for strerror_r says you should use the XSI
61 // version in portable code. However, it's impossible to do that if
62 // _GNU_SOURCE is defined so we use C++ overloading to decide what to do
63 // depending on the return type
64 [[maybe_unused]] static inline QString fromstrerror_helper(int, const QByteArray &buf)
65 {
66 return QString::fromLocal8Bit(buf);
67 }
68 [[maybe_unused]] static inline QString fromstrerror_helper(const char *str, const QByteArray &)
69 {
70 return QString::fromLocal8Bit(str);
71 }
72}
73#endif
74
75#ifdef Q_OS_WIN
76static QString windowsErrorString(int errorCode)
77{
78 QString ret;
79 wchar_t *string = nullptr;
80 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
81 NULL,
82 errorCode,
83 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
84 (LPWSTR)&string,
85 0,
86 NULL);
87 ret = QString::fromWCharArray(string);
88 LocalFree((HLOCAL)string);
89
90 if (ret.isEmpty() && errorCode == ERROR_MOD_NOT_FOUND)
91 ret = QString::fromLatin1("The specified module could not be found.");
92 if (ret.endsWith(QLatin1String("\r\n")))
93 ret.chop(2);
94 if (ret.isEmpty())
95 ret = QString::fromLatin1("Unknown error 0x%1.")
96 .arg(unsigned(errorCode), 8, 16, QLatin1Char('0'));
97 return ret;
98}
99#endif
100
101static QString standardLibraryErrorString(int errorCode)
102{
103 const char *s = nullptr;
104 QString ret;
105 switch (errorCode) {
106 case 0:
107 break;
108 case EACCES:
109 s = QT_TRANSLATE_NOOP("QIODevice", "Permission denied");
110 break;
111 case EMFILE:
112 s = QT_TRANSLATE_NOOP("QIODevice", "Too many open files");
113 break;
114 case ENOENT:
115 s = QT_TRANSLATE_NOOP("QIODevice", "No such file or directory");
116 break;
117 case ENOSPC:
118 s = QT_TRANSLATE_NOOP("QIODevice", "No space left on device");
119 break;
120 default: {
121 #if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX)
122 QByteArray buf(1024, Qt::Uninitialized);
123 ret = fromstrerror_helper(strerror_r(errorCode, buf.data(), buf.size()), buf);
124 #else
125 ret = QString::fromLocal8Bit(strerror(errorCode));
126 #endif
127 break; }
128 }
129 if (s) {
130 // ######## this breaks moc build currently
131 // ret = QCoreApplication::translate("QIODevice", s);
132 ret = QString::fromLatin1(s);
133 }
134 return ret.trimmed();
135}
136
137QString QSystemError::string(ErrorScope errorScope, int errorCode)
138{
139 switch (errorScope) {
140 case NativeError:
141#if defined(Q_OS_WIN)
142 return windowsErrorString(errorCode);
143#endif // else unix: native and standard library are the same
144 case StandardLibraryError:
145 return standardLibraryErrorString(errorCode);
146 default:
147 qWarning("invalid error scope");
148 Q_FALLTHROUGH();
149 case NoError:
150 return QLatin1String("No error");
151 }
152}
153
154QString QSystemError::stdString(int errorCode)
155{
156 return standardLibraryErrorString(errorCode == -1 ? errno : errorCode);
157}
158
159#ifdef Q_OS_WIN
160QString QSystemError::windowsString(int errorCode)
161{
162 return windowsErrorString(errorCode == -1 ? GetLastError() : errorCode);
163}
164
165QString qt_error_string(int code)
166{
167 return windowsErrorString(code == -1 ? GetLastError() : code);
168}
169#else
170QString qt_error_string(int code)
171{
172 return standardLibraryErrorString(code == -1 ? errno : code);
173}
174#endif
175
176QT_END_NAMESPACE
177