No such SHA1 was found

1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the QtCore module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
#include "qsystemsemaphore.h"
43
#include "qsystemsemaphore_p.h"
44
45
#include <qcoreapplication.h>
46
#include <qdebug.h>
47
#include <qfile.h>
48
49
#ifndef QT_NO_SYSTEMSEMAPHORE
50
51
#include <sys/types.h>
52
#include <sys/ipc.h>
53
#ifndef QT_POSIX_IPC
54
#include <sys/sem.h>
55
#endif
56
#include <fcntl.h>
57
#include <errno.h>
58
59
#include "private/qcore_unix_p.h"
60
61
// OpenBSD 4.2 doesn't define EIDRM, see BUGS section:
62
// http://www.openbsd.org/cgi-bin/man.cgi?query=semop&manpath=OpenBSD+4.2
63
#if defined(Q_OS_OPENBSD) && !defined(EIDRM)
64
#define EIDRM EINVAL
65
#endif
66
67
//#define QSYSTEMSEMAPHORE_DEBUG
68
69
QT_BEGIN_NAMESPACE
70
71
QSystemSemaphorePrivate::QSystemSemaphorePrivate() :
72
#ifndef QT_POSIX_IPC
73
    unix_key(-1), semaphore(-1), createdFile(false),
74
#else
75
    semaphore(SEM_FAILED),
76
#endif
77
    createdSemaphore(false), error(QSystemSemaphore::NoError)
78
{
79
}
80
81
void QSystemSemaphorePrivate::setErrorString(const QString &function)
82
{
83
    // EINVAL is handled in functions so they can give better error strings
84
    switch (errno) {
85
    case EPERM:
86
    case EACCES:
87
        errorString = QCoreApplication::translate("QSystemSemaphore", "%1: permission denied").arg(function);
88
        error = QSystemSemaphore::PermissionDenied;
89
        break;
90
    case EEXIST:
91
        errorString = QCoreApplication::translate("QSystemSemaphore", "%1: already exists").arg(function);
92
        error = QSystemSemaphore::AlreadyExists;
93
        break;
94
    case ENOENT:
95
        errorString = QCoreApplication::translate("QSystemSemaphore", "%1: does not exist").arg(function);
96
        error = QSystemSemaphore::NotFound;
97
        break;
98
    case ERANGE:
99
    case ENOMEM:
100
    case ENOSPC:
101
    case EMFILE:
102
    case ENFILE:
103
    case EOVERFLOW:
104
        errorString = QCoreApplication::translate("QSystemSemaphore", "%1: out of resources").arg(function);
105
        error = QSystemSemaphore::OutOfResources;
106
        break;
107
    case ENAMETOOLONG:
108
        errorString = QCoreApplication::translate("QSystemSemaphore", "%1: name error").arg(function);
109
        error = QSystemSemaphore::KeyError;
110
        break;
111
    default:
112
        errorString = QCoreApplication::translate("QSystemSemaphore", "%1: unknown error %2").arg(function).arg(errno);
113
        error = QSystemSemaphore::UnknownError;
114
#ifdef QSYSTEMSEMAPHORE_DEBUG
115
        qDebug() << errorString << "key" << key << "errno" << errno << EINVAL;
116
#endif
117
        break;
118
    }
119
}
120
121
/*!
122
    \internal
123
124
    Initialise the semaphore
125
*/
126
#ifndef QT_POSIX_IPC
127
key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode)
128
{
129
    if (-1 != unix_key)
130
        return unix_key;
131
132
    if (key.isEmpty()) {
133
        errorString = QCoreApplication::tr("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle"));
134
        error = QSystemSemaphore::KeyError;
135
        return -1;
136
    }
137
138
    // ftok requires that an actual file exists somewhere
139
    int built = QSharedMemoryPrivate::createUnixKeyFile(fileName);
140
    if (-1 == built) {
141
        errorString = QCoreApplication::tr("%1: unable to make key", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle"));
142
        error = QSystemSemaphore::KeyError;
143
        return -1;
144
    }
145
    createdFile = (1 == built);
146
147
    // Get the unix key for the created file
148
    unix_key = ftok(QFile::encodeName(fileName).constData(), 'Q');
149
    if (-1 == unix_key) {
150
        errorString = QCoreApplication::tr("%1: ftok failed", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle"));
151
        error = QSystemSemaphore::KeyError;
152
        return -1;
153
    }
154
155
    // Get semaphore
156
    semaphore = semget(unix_key, 1, 0666 | IPC_CREAT | IPC_EXCL);
157
    if (-1 == semaphore) {
158
        if (errno == EEXIST)
159
            semaphore = semget(unix_key, 1, 0666 | IPC_CREAT);
160
        if (-1 == semaphore) {
161
            setErrorString(QLatin1String("QSystemSemaphore::handle"));
162
            cleanHandle();
163
            return -1;
164
        }
165
        if (mode == QSystemSemaphore::Create) {
166
            createdSemaphore = true;
167
            createdFile = true;
168
        }
169
    } else {
170
        createdSemaphore = true;
171
        // Force cleanup of file, it is possible that it can be left over from a crash
172
        createdFile = true;
173
    }
174
175
    // Created semaphore so initialize its value.
176
    if (createdSemaphore && initialValue >= 0) {
177
        qt_semun init_op;
178
        init_op.val = initialValue;
179
        if (-1 == semctl(semaphore, 0, SETVAL, init_op)) {
180
            setErrorString(QLatin1String("QSystemSemaphore::handle"));
181
            cleanHandle();
182
            return -1;
183
        }
184
    }
185
186
    return unix_key;
187
}
188
#else
189
bool QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode)
190
{
191
    if (semaphore != SEM_FAILED)
192
        return true;  // we already have a semaphore
193
194
    if (fileName.isEmpty()) {
195
        errorString = QCoreApplication::tr("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle"));
196
        error = QSystemSemaphore::KeyError;
197
        return false;
198
    }
199
200
    QByteArray semName = QFile::encodeName(fileName);
201
202
    // Always try with O_EXCL so we know whether we created the semaphore.
203
    int oflag = O_CREAT | O_EXCL;
204
    for (int tryNum = 0, maxTries = 1; tryNum < maxTries; ++tryNum) {
205
        do {
206
            semaphore = sem_open(semName.constData(), oflag, 0666, initialValue);
207
        } while (semaphore == SEM_FAILED && errno == EINTR);
208
        if (semaphore == SEM_FAILED && errno == EEXIST) {
209
            if (mode == QSystemSemaphore::Create) {
210
                if (sem_unlink(semName.constData()) == -1 && errno != ENOENT) {
211
                    setErrorString(QLatin1String("QSystemSemaphore::handle (sem_unlink)"));
212
                    return false;
213
                }
214
                // Race condition: the semaphore might be recreated before
215
                // we call sem_open again, so we'll retry several times.
216
                maxTries = 3;
217
            } else {
218
                // Race condition: if it no longer exists at the next sem_open
219
                // call, we won't realize we created it, so we'll leak it later.
220
                oflag &= ~O_EXCL;
221
                maxTries = 2;
222
            }
223
        } else {
224
            break;
225
        }
226
    }
227
    if (semaphore == SEM_FAILED) {
228
        setErrorString(QLatin1String("QSystemSemaphore::handle"));
229
        return false;
230
    }
231
232
    createdSemaphore = (oflag & O_EXCL) != 0;
233
    return true;
234
}
235
#endif // QT_POSIX_IPC
236
237
/*!
238
    \internal
239
240
    Clean up the semaphore
241
*/
242
void QSystemSemaphorePrivate::cleanHandle()
243
{
244
#ifndef QT_POSIX_IPC
245
    unix_key = -1;
246
247
    // remove the file if we made it
248
    if (createdFile) {
249
        QFile::remove(fileName);
250
        createdFile = false;
251
    }
252
253
    if (createdSemaphore) {
254
        if (-1 != semaphore) {
255
            if (-1 == semctl(semaphore, 0, IPC_RMID, 0)) {
256
                setErrorString(QLatin1String("QSystemSemaphore::cleanHandle"));
257
#ifdef QSYSTEMSEMAPHORE_DEBUG
258
                qDebug("QSystemSemaphore::cleanHandle semctl failed.");
259
#endif
260
            }
261
            semaphore = -1;
262
        }
263
        createdSemaphore = false;
264
    }
265
#else
266
    if (semaphore != SEM_FAILED) {
267
        if (sem_close(semaphore) == -1) {
268
            setErrorString(QLatin1String("QSystemSemaphore::cleanHandle (sem_close)"));
269
#ifdef QSYSTEMSEMAPHORE_DEBUG
270
            qDebug() << QLatin1String("QSystemSemaphore::cleanHandle sem_close failed.");
271
#endif
272
        }
273
        semaphore = SEM_FAILED;
274
    }
275
276
    if (createdSemaphore) {
277
        if (sem_unlink(QFile::encodeName(fileName).constData()) == -1 && errno != ENOENT) {
278
            setErrorString(QLatin1String("QSystemSemaphore::cleanHandle (sem_unlink)"));
279
#ifdef QSYSTEMSEMAPHORE_DEBUG
280
            qDebug() << QLatin1String("QSystemSemaphore::cleanHandle sem_unlink failed.");
281
#endif
282
        }
283
        createdSemaphore = false;
284
    }
285
#endif // QT_POSIX_IPC
286
}
287
288
/*!
289
    \internal
290
*/
291
bool QSystemSemaphorePrivate::modifySemaphore(int count)
292
{
293
#ifndef QT_POSIX_IPC
294
    if (-1 == handle())
295
        return false;
296
297
    struct sembuf operation;
298
    operation.sem_num = 0;
299
    operation.sem_op = count;
300
    operation.sem_flg = SEM_UNDO;
301
302
    register int res;
303
    EINTR_LOOP(res, semop(semaphore, &operation, 1));
304
    if (-1 == res) {
305
        // If the semaphore was removed be nice and create it and then modifySemaphore again
306
        if (errno == EINVAL || errno == EIDRM) {
307
            semaphore = -1;
308
            cleanHandle();
309
            handle();
310
            return modifySemaphore(count);
311
        }
312
        setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore"));
313
#ifdef QSYSTEMSEMAPHORE_DEBUG
314
        qDebug() << QLatin1String("QSystemSemaphore::modify failed") << count << semctl(semaphore, 0, GETVAL) << errno << EIDRM << EINVAL;
315
#endif
316
        return false;
317
    }
318
#else
319
    if (!handle())
320
        return false;
321
322
    if (count > 0) {
323
        int cnt = count;
324
        do {
325
            if (sem_post(semaphore) == -1) {
326
                setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore (sem_post)"));
327
#ifdef QSYSTEMSEMAPHORE_DEBUG
328
                qDebug() << QLatin1String("QSystemSemaphore::modify sem_post failed") << count << errno;
329
#endif
330
                // rollback changes to preserve the SysV semaphore behavior
331
                for ( ; cnt < count; ++cnt) {
332
                    register int res;
333
                    EINTR_LOOP(res, sem_wait(semaphore));
334
                }
335
                return false;
336
            }
337
            --cnt;
338
        } while (cnt > 0);
339
    } else {
340
        register int res;
341
        EINTR_LOOP(res, sem_wait(semaphore));
342
        if (res == -1) {
343
            // If the semaphore was removed be nice and create it and then modifySemaphore again
344
            if (errno == EINVAL || errno == EIDRM) {
345
                semaphore = SEM_FAILED;
346
                return modifySemaphore(count);
347
            }
348
            setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore (sem_wait)"));
349
#ifdef QSYSTEMSEMAPHORE_DEBUG
350
            qDebug() << QLatin1String("QSystemSemaphore::modify sem_wait failed") << count << errno;
351
#endif
352
            return false;
353
        }
354
    }
355
#endif // QT_POSIX_IPC
356
357
    return true;
358
}
359
360
QT_END_NAMESPACE
361
362
#endif // QT_NO_SYSTEMSEMAPHORE