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 : #ifdef HAVE_CONFIG_H
25 : #include "config.h"
26 : #endif
27 :
28 : #include <dataprovider.h>
29 :
30 : #include <error.h>
31 :
32 : #include <QIODevice>
33 : #include <QProcess>
34 :
35 : #include <cstdio>
36 : #include <cstring>
37 : #include <cassert>
38 :
39 : using namespace QGpgME;
40 : using namespace GpgME;
41 :
42 : //
43 : //
44 : // QByteArrayDataProvider
45 : //
46 : //
47 :
48 26 : static bool resizeAndInit(QByteArray &ba, size_t newSize)
49 : {
50 26 : const size_t oldSize = ba.size();
51 26 : ba.resize(newSize);
52 26 : const bool ok = (newSize == static_cast<size_t>(ba.size()));
53 26 : if (ok) {
54 26 : memset(ba.data() + oldSize, 0, newSize - oldSize);
55 : }
56 26 : return ok;
57 : }
58 :
59 45 : QByteArrayDataProvider::QByteArrayDataProvider()
60 45 : : GpgME::DataProvider(), mOff(0) {}
61 :
62 0 : QByteArrayDataProvider::QByteArrayDataProvider(const QByteArray &initialData)
63 0 : : GpgME::DataProvider(), mArray(initialData), mOff(0) {}
64 :
65 45 : QByteArrayDataProvider::~QByteArrayDataProvider() {}
66 :
67 0 : ssize_t QByteArrayDataProvider::read(void *buffer, size_t bufSize)
68 : {
69 : #ifndef NDEBUG
70 : //qDebug( "QByteArrayDataProvider::read( %p, %d )", buffer, bufSize );
71 : #endif
72 0 : if (bufSize == 0) {
73 0 : return 0;
74 : }
75 0 : if (!buffer) {
76 0 : Error::setSystemError(GPG_ERR_EINVAL);
77 0 : return -1;
78 : }
79 0 : if (mOff >= mArray.size()) {
80 0 : return 0; // EOF
81 : }
82 0 : size_t amount = qMin(bufSize, static_cast<size_t>(mArray.size() - mOff));
83 0 : assert(amount > 0);
84 0 : memcpy(buffer, mArray.data() + mOff, amount);
85 0 : mOff += amount;
86 0 : return amount;
87 : }
88 :
89 26 : ssize_t QByteArrayDataProvider::write(const void *buffer, size_t bufSize)
90 : {
91 : #ifndef NDEBUG
92 : //qDebug( "QByteArrayDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
93 : #endif
94 26 : if (bufSize == 0) {
95 0 : return 0;
96 : }
97 26 : if (!buffer) {
98 0 : Error::setSystemError(GPG_ERR_EINVAL);
99 0 : return -1;
100 : }
101 26 : if (mOff >= mArray.size()) {
102 26 : resizeAndInit(mArray, mOff + bufSize);
103 : }
104 26 : if (mOff >= mArray.size()) {
105 0 : Error::setSystemError(GPG_ERR_EIO);
106 0 : return -1;
107 : }
108 26 : assert(bufSize <= static_cast<size_t>(mArray.size()) - mOff);
109 26 : memcpy(mArray.data() + mOff, buffer, bufSize);
110 26 : mOff += bufSize;
111 26 : return bufSize;
112 : }
113 :
114 90 : off_t QByteArrayDataProvider::seek(off_t offset, int whence)
115 : {
116 : #ifndef NDEBUG
117 : //qDebug( "QByteArrayDataProvider::seek( %d, %d )", int(offset), whence );
118 : #endif
119 90 : int newOffset = mOff;
120 90 : switch (whence) {
121 : case SEEK_SET:
122 45 : newOffset = offset;
123 45 : break;
124 : case SEEK_CUR:
125 0 : newOffset += offset;
126 0 : break;
127 : case SEEK_END:
128 45 : newOffset = mArray.size() + offset;
129 45 : break;
130 : default:
131 0 : Error::setSystemError(GPG_ERR_EINVAL);
132 0 : return (off_t) - 1;
133 : }
134 90 : return mOff = newOffset;
135 : }
136 :
137 45 : void QByteArrayDataProvider::release()
138 : {
139 : #ifndef NDEBUG
140 : //qDebug( "QByteArrayDataProvider::release()" );
141 : #endif
142 45 : mArray = QByteArray();
143 45 : }
144 :
145 : //
146 : //
147 : // QIODeviceDataProvider
148 : //
149 : //
150 :
151 22 : QIODeviceDataProvider::QIODeviceDataProvider(const std::shared_ptr<QIODevice> &io)
152 : : GpgME::DataProvider(),
153 : mIO(io),
154 : mErrorOccurred(false),
155 22 : mHaveQProcess(qobject_cast<QProcess *>(io.get()))
156 : {
157 22 : assert(mIO);
158 22 : }
159 :
160 22 : QIODeviceDataProvider::~QIODeviceDataProvider() {}
161 :
162 110 : bool QIODeviceDataProvider::isSupported(Operation op) const
163 : {
164 110 : const QProcess *const proc = qobject_cast<QProcess *>(mIO.get());
165 110 : bool canRead = true;
166 110 : if (proc) {
167 0 : canRead = proc->readChannel() == QProcess::StandardOutput;
168 : }
169 :
170 110 : switch (op) {
171 22 : case Read: return mIO->isReadable() && canRead;
172 22 : case Write: return mIO->isWritable();
173 44 : case Seek: return !mIO->isSequential();
174 22 : case Release: return true;
175 0 : default: return false;
176 : }
177 : }
178 :
179 0 : static qint64 blocking_read(const std::shared_ptr<QIODevice> &io, char *buffer, qint64 maxSize)
180 : {
181 0 : while (!io->bytesAvailable()) {
182 0 : if (!io->waitForReadyRead(-1)) {
183 0 : if (const QProcess *const p = qobject_cast<QProcess *>(io.get())) {
184 0 : if (p->error() == QProcess::UnknownError &&
185 0 : p->exitStatus() == QProcess::NormalExit &&
186 0 : p->exitCode() == 0) {
187 0 : return 0;
188 : } else {
189 0 : Error::setSystemError(GPG_ERR_EIO);
190 0 : return -1;
191 : }
192 : } else {
193 0 : return 0; // assume EOF (loses error cases :/ )
194 : }
195 : }
196 : }
197 0 : return io->read(buffer, maxSize);
198 : }
199 :
200 297 : ssize_t QIODeviceDataProvider::read(void *buffer, size_t bufSize)
201 : {
202 : #ifndef NDEBUG
203 : //qDebug( "QIODeviceDataProvider::read( %p, %lu )", buffer, bufSize );
204 : #endif
205 297 : if (bufSize == 0) {
206 0 : return 0;
207 : }
208 297 : if (!buffer) {
209 0 : Error::setSystemError(GPG_ERR_EINVAL);
210 0 : return -1;
211 : }
212 : const qint64 numRead = mHaveQProcess
213 0 : ? blocking_read(mIO, static_cast<char *>(buffer), bufSize)
214 297 : : mIO->read(static_cast<char *>(buffer), bufSize);
215 :
216 : //workaround: some QIODevices (known example: QProcess) might not return 0 (EOF), but immediately -1 when finished. If no
217 : //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
218 :
219 297 : ssize_t rc = numRead;
220 297 : if (numRead < 0 && !Error::hasSystemError()) {
221 0 : if (mErrorOccurred) {
222 0 : Error::setSystemError(GPG_ERR_EIO);
223 : } else {
224 0 : rc = 0;
225 : }
226 : }
227 297 : if (numRead < 0) {
228 0 : mErrorOccurred = true;
229 : }
230 297 : return rc;
231 : }
232 :
233 3 : ssize_t QIODeviceDataProvider::write(const void *buffer, size_t bufSize)
234 : {
235 : #ifndef NDEBUG
236 : //qDebug( "QIODeviceDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
237 : #endif
238 3 : if (bufSize == 0) {
239 0 : return 0;
240 : }
241 3 : if (!buffer) {
242 0 : Error::setSystemError(GPG_ERR_EINVAL);
243 0 : return -1;
244 : }
245 :
246 3 : return mIO->write(static_cast<const char *>(buffer), bufSize);
247 : }
248 :
249 44 : off_t QIODeviceDataProvider::seek(off_t offset, int whence)
250 : {
251 : #ifndef NDEBUG
252 : //qDebug( "QIODeviceDataProvider::seek( %d, %d )", int(offset), whence );
253 : #endif
254 44 : if (mIO->isSequential()) {
255 0 : Error::setSystemError(GPG_ERR_ESPIPE);
256 0 : return (off_t) - 1;
257 : }
258 44 : qint64 newOffset = mIO->pos();
259 44 : switch (whence) {
260 : case SEEK_SET:
261 22 : newOffset = offset;
262 22 : break;
263 : case SEEK_CUR:
264 0 : newOffset += offset;
265 0 : break;
266 : case SEEK_END:
267 22 : newOffset = mIO->size() + offset;
268 22 : break;
269 : default:
270 0 : Error::setSystemError(GPG_ERR_EINVAL);
271 0 : return (off_t) - 1;
272 : }
273 44 : if (!mIO->seek(newOffset)) {
274 0 : Error::setSystemError(GPG_ERR_EINVAL);
275 0 : return (off_t) - 1;
276 : }
277 44 : return newOffset;
278 : }
279 :
280 22 : void QIODeviceDataProvider::release()
281 : {
282 : #ifndef NDEBUG
283 : //qDebug( "QIODeviceDataProvider::release()" );
284 : #endif
285 22 : mIO->close();
286 22 : }
|