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 
50 QT_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
54 namespace {
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
fromstrerror_helper(int,const QByteArray & buf)64     static inline Q_DECL_UNUSED QString fromstrerror_helper(int, const QByteArray &buf)
65     {
66         return QString::fromLocal8Bit(buf);
67     }
fromstrerror_helper(const char * str,const QByteArray &)68     static inline Q_DECL_UNUSED QString fromstrerror_helper(const char *str, const QByteArray &)
69     {
70         return QString::fromLocal8Bit(str);
71     }
72 }
73 #endif
74 
75 #ifdef Q_OS_WIN
windowsErrorString(int errorCode)76 static QString windowsErrorString(int errorCode)
77 {
78     QString ret;
79 #ifndef Q_OS_WINRT
80     wchar_t *string = 0;
81     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
82                   NULL,
83                   errorCode,
84                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
85                   (LPWSTR)&string,
86                   0,
87                   NULL);
88     ret = QString::fromWCharArray(string);
89     LocalFree((HLOCAL)string);
90 #else
91     wchar_t errorString[1024];
92     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
93                   NULL,
94                   errorCode,
95                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
96                   (LPWSTR)&errorString,
97                   sizeof(errorString)/sizeof(wchar_t),
98                   NULL);
99     ret = QString::fromWCharArray(errorString);
100 #endif  // Q_OS_WINRT
101 
102     if (ret.isEmpty() && errorCode == ERROR_MOD_NOT_FOUND)
103         ret = QString::fromLatin1("The specified module could not be found.");
104     if (ret.endsWith(QLatin1String("\r\n")))
105         ret.chop(2);
106     if (ret.isEmpty())
107         ret = QString::fromLatin1("Unknown error 0x%1.")
108                 .arg(unsigned(errorCode), 8, 16, QLatin1Char('0'));
109     return ret;
110 }
111 #endif
112 
standardLibraryErrorString(int errorCode)113 static QString standardLibraryErrorString(int errorCode)
114 {
115     const char *s = nullptr;
116     QString ret;
117     switch (errorCode) {
118     case 0:
119         break;
120     case EACCES:
121         s = QT_TRANSLATE_NOOP("QIODevice", "Permission denied");
122         break;
123     case EMFILE:
124         s = QT_TRANSLATE_NOOP("QIODevice", "Too many open files");
125         break;
126     case ENOENT:
127         s = QT_TRANSLATE_NOOP("QIODevice", "No such file or directory");
128         break;
129     case ENOSPC:
130         s = QT_TRANSLATE_NOOP("QIODevice", "No space left on device");
131         break;
132     default: {
133       #if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX)
134             QByteArray buf(1024, Qt::Uninitialized);
135             ret = fromstrerror_helper(strerror_r(errorCode, buf.data(), buf.size()), buf);
136       #else
137             ret = QString::fromLocal8Bit(strerror(errorCode));
138       #endif
139     break; }
140     }
141     if (s) {
142         // ######## this breaks moc build currently
143         // ret = QCoreApplication::translate("QIODevice", s);
144         ret = QString::fromLatin1(s);
145     }
146     return ret.trimmed();
147 }
148 
string(ErrorScope errorScope,int errorCode)149 QString QSystemError::string(ErrorScope errorScope, int errorCode)
150 {
151     switch(errorScope) {
152     case NativeError:
153 #if defined (Q_OS_WIN)
154         return windowsErrorString(errorCode);
155 #endif // else unix: native and standard library are the same
156     case StandardLibraryError:
157         return standardLibraryErrorString(errorCode);
158     default:
159         qWarning("invalid error scope");
160         Q_FALLTHROUGH();
161     case NoError:
162         return QLatin1String("No error");
163     }
164 }
165 
stdString(int errorCode)166 QString QSystemError::stdString(int errorCode)
167 {
168     return standardLibraryErrorString(errorCode == -1 ? errno : errorCode);
169 }
170 
171 #ifdef Q_OS_WIN
windowsString(int errorCode)172 QString QSystemError::windowsString(int errorCode)
173 {
174     return windowsErrorString(errorCode == -1 ? GetLastError() : errorCode);
175 }
176 
qt_error_string(int code)177 QString qt_error_string(int code)
178 {
179     return windowsErrorString(code == -1 ? GetLastError() : code);
180 }
181 #else
qt_error_string(int code)182 QString qt_error_string(int code)
183 {
184     return standardLibraryErrorString(code == -1 ? errno : code);
185 }
186 #endif
187 
188 QT_END_NAMESPACE
189