Line data Source code
1 : /* dataprovider.cpp
2 : Copyright (C) 2004 Klar�vdalens Datakonsult AB
3 : Copyright (c) 2016 Intevation GmbH
4 :
5 : This file is part of QGPGME.
6 :
7 : QGPGME is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Library General Public License as published
9 : by the Free Software Foundation; either version 2 of the License, or
10 : (at your option) any later version.
11 :
12 : QGPGME is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU Library General Public License for more details.
16 :
17 : You should have received a copy of the GNU Library General Public License
18 : along with QGPGME; see the file COPYING.LIB. If not, write to the
19 : Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 : Boston, MA 02110-1301, USA. */
21 :
22 : // -*- c++ -*-
23 :
24 : #include <dataprovider.h>
25 :
26 : #include <error.h>
27 :
28 : #include <QIODevice>
29 : #include <QProcess>
30 :
31 : #include <cstdio>
32 : #include <cstring>
33 : #include <cassert>
34 :
35 : using namespace QGpgME;
36 : using namespace GpgME;
37 :
38 : //
39 : //
40 : // QByteArrayDataProvider
41 : //
42 : //
43 :
44 25 : static bool resizeAndInit(QByteArray &ba, size_t newSize)
45 : {
46 25 : const size_t oldSize = ba.size();
47 25 : ba.resize(newSize);
48 25 : const bool ok = (newSize == static_cast<size_t>(ba.size()));
49 25 : if (ok) {
50 25 : memset(ba.data() + oldSize, 0, newSize - oldSize);
51 : }
52 25 : return ok;
53 : }
54 :
55 43 : QByteArrayDataProvider::QByteArrayDataProvider()
56 43 : : GpgME::DataProvider(), mOff(0) {}
57 :
58 0 : QByteArrayDataProvider::QByteArrayDataProvider(const QByteArray &initialData)
59 0 : : GpgME::DataProvider(), mArray(initialData), mOff(0) {}
60 :
61 43 : QByteArrayDataProvider::~QByteArrayDataProvider() {}
62 :
63 0 : ssize_t QByteArrayDataProvider::read(void *buffer, size_t bufSize)
64 : {
65 : #ifndef NDEBUG
66 : //qDebug( "QByteArrayDataProvider::read( %p, %d )", buffer, bufSize );
67 : #endif
68 0 : if (bufSize == 0) {
69 0 : return 0;
70 : }
71 0 : if (!buffer) {
72 0 : Error::setSystemError(GPG_ERR_EINVAL);
73 0 : return -1;
74 : }
75 0 : if (mOff >= mArray.size()) {
76 0 : return 0; // EOF
77 : }
78 0 : size_t amount = qMin(bufSize, static_cast<size_t>(mArray.size() - mOff));
79 0 : assert(amount > 0);
80 0 : memcpy(buffer, mArray.data() + mOff, amount);
81 0 : mOff += amount;
82 0 : return amount;
83 : }
84 :
85 25 : ssize_t QByteArrayDataProvider::write(const void *buffer, size_t bufSize)
86 : {
87 : #ifndef NDEBUG
88 : //qDebug( "QByteArrayDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
89 : #endif
90 25 : if (bufSize == 0) {
91 0 : return 0;
92 : }
93 25 : if (!buffer) {
94 0 : Error::setSystemError(GPG_ERR_EINVAL);
95 0 : return -1;
96 : }
97 25 : if (mOff >= mArray.size()) {
98 25 : resizeAndInit(mArray, mOff + bufSize);
99 : }
100 25 : if (mOff >= mArray.size()) {
101 0 : Error::setSystemError(GPG_ERR_EIO);
102 0 : return -1;
103 : }
104 25 : assert(bufSize <= static_cast<size_t>(mArray.size()) - mOff);
105 25 : memcpy(mArray.data() + mOff, buffer, bufSize);
106 25 : mOff += bufSize;
107 25 : return bufSize;
108 : }
109 :
110 86 : off_t QByteArrayDataProvider::seek(off_t offset, int whence)
111 : {
112 : #ifndef NDEBUG
113 : //qDebug( "QByteArrayDataProvider::seek( %d, %d )", int(offset), whence );
114 : #endif
115 86 : int newOffset = mOff;
116 86 : switch (whence) {
117 : case SEEK_SET:
118 43 : newOffset = offset;
119 43 : break;
120 : case SEEK_CUR:
121 0 : newOffset += offset;
122 0 : break;
123 : case SEEK_END:
124 43 : newOffset = mArray.size() + offset;
125 43 : break;
126 : default:
127 0 : Error::setSystemError(GPG_ERR_EINVAL);
128 0 : return (off_t) - 1;
129 : }
130 86 : return mOff = newOffset;
131 : }
132 :
133 43 : void QByteArrayDataProvider::release()
134 : {
135 : #ifndef NDEBUG
136 : //qDebug( "QByteArrayDataProvider::release()" );
137 : #endif
138 43 : mArray = QByteArray();
139 43 : }
140 :
141 : //
142 : //
143 : // QIODeviceDataProvider
144 : //
145 : //
146 :
147 21 : QIODeviceDataProvider::QIODeviceDataProvider(const std::shared_ptr<QIODevice> &io)
148 : : GpgME::DataProvider(),
149 : mIO(io),
150 : mErrorOccurred(false),
151 21 : mHaveQProcess(qobject_cast<QProcess *>(io.get()))
152 : {
153 21 : assert(mIO);
154 21 : }
155 :
156 21 : QIODeviceDataProvider::~QIODeviceDataProvider() {}
157 :
158 105 : bool QIODeviceDataProvider::isSupported(Operation op) const
159 : {
160 105 : const QProcess *const proc = qobject_cast<QProcess *>(mIO.get());
161 105 : bool canRead = true;
162 105 : if (proc) {
163 0 : canRead = proc->readChannel() == QProcess::StandardOutput;
164 : }
165 :
166 105 : switch (op) {
167 21 : case Read: return mIO->isReadable() && canRead;
168 21 : case Write: return mIO->isWritable();
169 42 : case Seek: return !mIO->isSequential();
170 21 : case Release: return true;
171 0 : default: return false;
172 : }
173 : }
174 :
175 0 : static qint64 blocking_read(const std::shared_ptr<QIODevice> &io, char *buffer, qint64 maxSize)
176 : {
177 0 : while (!io->bytesAvailable()) {
178 0 : if (!io->waitForReadyRead(-1)) {
179 0 : if (const QProcess *const p = qobject_cast<QProcess *>(io.get())) {
180 0 : if (p->error() == QProcess::UnknownError &&
181 0 : p->exitStatus() == QProcess::NormalExit &&
182 0 : p->exitCode() == 0) {
183 0 : return 0;
184 : } else {
185 0 : Error::setSystemError(GPG_ERR_EIO);
186 0 : return -1;
187 : }
188 : } else {
189 0 : return 0; // assume EOF (loses error cases :/ )
190 : }
191 : }
192 : }
193 0 : return io->read(buffer, maxSize);
194 : }
195 :
196 295 : ssize_t QIODeviceDataProvider::read(void *buffer, size_t bufSize)
197 : {
198 : #ifndef NDEBUG
199 : //qDebug( "QIODeviceDataProvider::read( %p, %lu )", buffer, bufSize );
200 : #endif
201 295 : if (bufSize == 0) {
202 0 : return 0;
203 : }
204 295 : if (!buffer) {
205 0 : Error::setSystemError(GPG_ERR_EINVAL);
206 0 : return -1;
207 : }
208 : const qint64 numRead = mHaveQProcess
209 0 : ? blocking_read(mIO, static_cast<char *>(buffer), bufSize)
210 295 : : mIO->read(static_cast<char *>(buffer), bufSize);
211 :
212 : //workaround: some QIODevices (known example: QProcess) might not return 0 (EOF), but immediately -1 when finished. If no
213 : //errno is set, gpgme doesn't detect the error and loops forever. So return 0 on the very first -1 in case errno is 0
214 :
215 295 : ssize_t rc = numRead;
216 295 : if (numRead < 0 && !Error::hasSystemError()) {
217 0 : if (mErrorOccurred) {
218 0 : Error::setSystemError(GPG_ERR_EIO);
219 : } else {
220 0 : rc = 0;
221 : }
222 : }
223 295 : if (numRead < 0) {
224 0 : mErrorOccurred = true;
225 : }
226 295 : return rc;
227 : }
228 :
229 2 : ssize_t QIODeviceDataProvider::write(const void *buffer, size_t bufSize)
230 : {
231 : #ifndef NDEBUG
232 : //qDebug( "QIODeviceDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
233 : #endif
234 2 : if (bufSize == 0) {
235 0 : return 0;
236 : }
237 2 : if (!buffer) {
238 0 : Error::setSystemError(GPG_ERR_EINVAL);
239 0 : return -1;
240 : }
241 :
242 2 : return mIO->write(static_cast<const char *>(buffer), bufSize);
243 : }
244 :
245 42 : off_t QIODeviceDataProvider::seek(off_t offset, int whence)
246 : {
247 : #ifndef NDEBUG
248 : //qDebug( "QIODeviceDataProvider::seek( %d, %d )", int(offset), whence );
249 : #endif
250 42 : if (mIO->isSequential()) {
251 0 : Error::setSystemError(GPG_ERR_ESPIPE);
252 0 : return (off_t) - 1;
253 : }
254 42 : qint64 newOffset = mIO->pos();
255 42 : switch (whence) {
256 : case SEEK_SET:
257 21 : newOffset = offset;
258 21 : break;
259 : case SEEK_CUR:
260 0 : newOffset += offset;
261 0 : break;
262 : case SEEK_END:
263 21 : newOffset = mIO->size() + offset;
264 21 : break;
265 : default:
266 0 : Error::setSystemError(GPG_ERR_EINVAL);
267 0 : return (off_t) - 1;
268 : }
269 42 : if (!mIO->seek(newOffset)) {
270 0 : Error::setSystemError(GPG_ERR_EINVAL);
271 0 : return (off_t) - 1;
272 : }
273 42 : return newOffset;
274 : }
275 :
276 21 : void QIODeviceDataProvider::release()
277 : {
278 : #ifndef NDEBUG
279 : //qDebug( "QIODeviceDataProvider::release()" );
280 : #endif
281 21 : mIO->close();
282 21 : }
|