diff options
author | João Abecasis <joao.abecasis@nokia.com> | 2012-01-16 17:52:29 +0100 |
---|---|---|
committer | João Abecasis <joao.abecasis@nokia.com> | 2012-01-16 17:53:41 +0100 |
commit | 5b250d497fd798c476765b22a2906e1c0ff1e432 (patch) | |
tree | fd4215ca375cc2402e536bf670c2977cf64ae2ef /src/corelib/io | |
parent | 2c52e9a5c1d6ef6cbf4577430e14027375465c96 (diff) | |
parent | 7a0099183a1c107126bda3b59a47651aac612426 (diff) |
Merge remote-tracking branch 'gerrit/master' into containers
Change-Id: I2d358b912f1055ee6021d13de2f66fd459aaa355
Diffstat (limited to 'src/corelib/io')
100 files changed, 1397 insertions, 3923 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index ef11621679..1d31e5d794 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -35,6 +35,7 @@ HEADERS += \ io/qfsfileengine_iterator_p.h \ io/qfilesystemwatcher.h \ io/qfilesystemwatcher_p.h \ + io/qfilesystemwatcher_polling_p.h \ io/qfilesystementry_p.h \ io/qfilesystemengine_p.h \ io/qfilesystemmetadata_p.h \ @@ -65,36 +66,39 @@ SOURCES += \ io/qfsfileengine.cpp \ io/qfsfileengine_iterator.cpp \ io/qfilesystemwatcher.cpp \ + io/qfilesystemwatcher_polling.cpp \ io/qfilesystementry.cpp \ io/qfilesystemengine.cpp win32 { SOURCES += io/qsettings_win.cpp - SOURCES += io/qprocess_win.cpp SOURCES += io/qfsfileengine_win.cpp SOURCES += io/qfilesystemwatcher_win.cpp HEADERS += io/qfilesystemwatcher_win_p.h + HEADERS += io/qwindowspipereader_p.h + SOURCES += io/qwindowspipereader.cpp HEADERS += io/qwindowspipewriter_p.h SOURCES += io/qwindowspipewriter.cpp SOURCES += io/qfilesystemengine_win.cpp SOURCES += io/qfilesystemiterator_win.cpp SOURCES += io/qstandardpaths_win.cpp -} else:unix { - SOURCES += io/qfsfileengine_unix.cpp - symbian { - SOURCES += io/qfilesystemengine_symbian.cpp - SOURCES += io/qprocess_symbian.cpp - SOURCES += io/qfilesystemiterator_symbian.cpp - } else { - SOURCES += io/qfilesystemengine_unix.cpp - SOURCES += io/qprocess_unix.cpp - SOURCES += io/qfilesystemiterator_unix.cpp - } + + wince* { + SOURCES += io/qprocess_wince.cpp + } else { + SOURCES += io/qprocess_win.cpp + } +} else:unix|integrity { + SOURCES += \ + io/qfsfileengine_unix.cpp \ + io/qfilesystemengine_unix.cpp \ + io/qprocess_unix.cpp \ + io/qfilesystemiterator_unix.cpp \ + !nacl:macx-*: { - HEADERS += io/qfilesystemwatcher_fsevents_p.h SOURCES += io/qfilesystemengine_mac.cpp - SOURCES += io/qsettings_mac.cpp io/qfilesystemwatcher_fsevents.cpp + SOURCES += io/qsettings_mac.cpp } macx-*: { SOURCES += io/qstandardpaths_mac.cpp @@ -102,14 +106,9 @@ win32 { SOURCES += io/qstandardpaths_unix.cpp } - linux-*:!symbian { - SOURCES += \ - io/qfilesystemwatcher_inotify.cpp \ - io/qfilesystemwatcher_dnotify.cpp - - HEADERS += \ - io/qfilesystemwatcher_inotify_p.h \ - io/qfilesystemwatcher_dnotify_p.h + linux-* { + SOURCES += io/qfilesystemwatcher_inotify.cpp + HEADERS += io/qfilesystemwatcher_inotify_p.h } !nacl { @@ -118,17 +117,5 @@ win32 { HEADERS += io/qfilesystemwatcher_kqueue_p.h } } - - symbian { - SOURCES += io/qfilesystemwatcher_symbian.cpp - HEADERS += io/qfilesystemwatcher_symbian_p.h - INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE - LIBS += -lplatformenv -lesock - } -} -integrity { - SOURCES += io/qfsfileengine_unix.cpp \ - io/qfsfileengine_iterator.cpp \ - io/qfilesystemengine_unix.cpp \ - io/qfilesystemiterator_unix.cpp } + diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index d2b250d336..c315d33606 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qabstractfileengine.h b/src/corelib/io/qabstractfileengine.h index cc167a2aa6..c9bab7d435 100644 --- a/src/corelib/io/qabstractfileengine.h +++ b/src/corelib/io/qabstractfileengine.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h index dd9a707316..72b8339e39 100644 --- a/src/corelib/io/qabstractfileengine_p.h +++ b/src/corelib/io/qabstractfileengine_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp index 35e7b6809c..a5e605b9d5 100644 --- a/src/corelib/io/qbuffer.cpp +++ b/src/corelib/io/qbuffer.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -143,12 +143,8 @@ QByteArray QBufferPrivate::peek(qint64 maxSize) QBuffer emits readyRead() when new data has arrived in the buffer. By connecting to this signal, you can use QBuffer to - store temporary data before processing it. For example, you can - pass the buffer to QFtp when downloading a file from an FTP - server. Whenever a new payload of data has been downloaded, - readyRead() is emitted, and you can process the data that just - arrived. QBuffer also emits bytesWritten() every time new data - has been written to the buffer. + store temporary data before processing it. QBuffer also emits + bytesWritten() every time new data has been written to the buffer. \sa QFile, QDataStream, QTextStream, QByteArray */ diff --git a/src/corelib/io/qbuffer.h b/src/corelib/io/qbuffer.h index 9227a2f3dc..b222c7d6ca 100644 --- a/src/corelib/io/qbuffer.h +++ b/src/corelib/io/qbuffer.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 0e0a47267a..fb2528e45f 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index 1ae0573f6c..30cf8417ad 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qdatastream_p.h b/src/corelib/io/qdatastream_p.h index d372d54e36..2501e98d1d 100644 --- a/src/corelib/io/qdatastream_p.h +++ b/src/corelib/io/qdatastream_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qdataurl.cpp b/src/corelib/io/qdataurl.cpp index ed8abdd839..7e856ad647 100644 --- a/src/corelib/io/qdataurl.cpp +++ b/src/corelib/io/qdataurl.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -51,51 +51,49 @@ QT_BEGIN_NAMESPACE Decode a data: URL into its mimetype and payload. Returns a null string if the URL could not be decoded. */ -Q_CORE_EXPORT QPair<QString, QByteArray> qDecodeDataUrl(const QUrl &uri) +Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray &payload) { - QString mimeType; - QByteArray payload; + if (uri.scheme() != QLatin1String("data") || !uri.host().isEmpty()) + return false; - if (uri.scheme() == QLatin1String("data") && uri.host().isEmpty()) { - mimeType = QLatin1String("text/plain;charset=US-ASCII"); + mimeType = QLatin1String("text/plain;charset=US-ASCII"); - // the following would have been the correct thing, but - // reality often differs from the specification. People have - // data: URIs with ? and # - //QByteArray data = QByteArray::fromPercentEncoding(uri.encodedPath()); - QByteArray data = QByteArray::fromPercentEncoding(uri.toEncoded()); + // the following would have been the correct thing, but + // reality often differs from the specification. People have + // data: URIs with ? and # + //QByteArray data = QByteArray::fromPercentEncoding(uri.encodedPath()); + QByteArray data = QByteArray::fromPercentEncoding(uri.toEncoded()); - // remove the data: scheme - data.remove(0, 5); + // remove the data: scheme + data.remove(0, 5); - // parse it: - int pos = data.indexOf(','); - if (pos != -1) { - payload = data.mid(pos + 1); - data.truncate(pos); - data = data.trimmed(); + // parse it: + int pos = data.indexOf(','); + if (pos != -1) { + payload = data.mid(pos + 1); + data.truncate(pos); + data = data.trimmed(); - // find out if the payload is encoded in Base64 - if (data.endsWith(";base64")) { - payload = QByteArray::fromBase64(payload); - data.chop(7); - } + // find out if the payload is encoded in Base64 + if (data.endsWith(";base64")) { + payload = QByteArray::fromBase64(payload); + data.chop(7); + } - if (data.toLower().startsWith("charset")) { - int i = 7; // strlen("charset") - while (data.at(i) == ' ') - ++i; - if (data.at(i) == '=') - data.prepend("text/plain;"); - } + if (data.toLower().startsWith("charset")) { + int i = 7; // strlen("charset") + while (data.at(i) == ' ') + ++i; + if (data.at(i) == '=') + data.prepend("text/plain;"); + } - if (!data.isEmpty()) - mimeType = QLatin1String(data.trimmed()); + if (!data.isEmpty()) + mimeType = QLatin1String(data.trimmed()); - } } - return QPair<QString,QByteArray>(mimeType,payload); + return true; } QT_END_NAMESPACE diff --git a/src/corelib/io/qdataurl_p.h b/src/corelib/io/qdataurl_p.h index d666d9e52a..b92f363e1d 100644 --- a/src/corelib/io/qdataurl_p.h +++ b/src/corelib/io/qdataurl_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE -Q_CORE_EXPORT QPair<QString, QByteArray> qDecodeDataUrl(const QUrl &url); +Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &url, QString &mimeType, QByteArray &payload); QT_END_NAMESPACE diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index a27716b8dc..8ca15b19ca 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 67221c7ce2..54663d5d65 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -129,10 +129,8 @@ public: inline QNoDebug(){} inline QNoDebug(const QDebug &){} inline ~QNoDebug(){} -#if !defined( QT_NO_TEXTSTREAM ) inline QNoDebug &operator<<(QTextStreamFunction) { return *this; } inline QNoDebug &operator<<(QTextStreamManipulator) { return *this; } -#endif inline QNoDebug &space() { return *this; } inline QNoDebug &nospace() { return *this; } inline QNoDebug &maybeSpace() { return *this; } @@ -141,8 +139,6 @@ public: inline QNoDebug &operator<<(const T &) { return *this; } }; -Q_CORE_EXPORT_INLINE QDebug qCritical() { return QDebug(QtCriticalMsg); } - inline QDebug &QDebug::operator=(const QDebug &other) { if (this != &other) { @@ -161,7 +157,7 @@ inline QDebug operator<<(QDebug debug, const QList<T> &list) #endif { debug.nospace() << '('; - for (Q_TYPENAME QList<T>::size_type i = 0; i < list.count(); ++i) { + for (typename QList<T>::size_type i = 0; i < list.count(); ++i) { if (i) debug << ", "; debug << list.at(i); @@ -275,17 +271,15 @@ inline QDebug operator<<(QDebug debug, const QFlags<T> &flags) return debug.space(); } -#if !defined(QT_NO_DEBUG_STREAM) +#if !defined(QT_NO_DEBUG_OUTPUT) && !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); } - -#else // QT_NO_DEBUG_STREAM +#else #undef qDebug inline QNoDebug qDebug() { return QNoDebug(); } #define qDebug QT_NO_QDEBUG_MACRO - #endif -#if !defined(QT_NO_WARNING_OUTPUT) +#if !defined(QT_NO_WARNING_OUTPUT) && !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT_INLINE QDebug qWarning() { return QDebug(QtWarningMsg); } #else #undef qWarning @@ -293,6 +287,11 @@ inline QNoDebug qWarning() { return QNoDebug(); } #define qWarning QT_NO_QWARNING_MACRO #endif +#if !defined(QT_NO_DEBUG_STREAM) +Q_CORE_EXPORT_INLINE QDebug qCritical() { return QDebug(QtCriticalMsg); } +#endif + + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 44992fcd14..d6979bad57 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -1502,7 +1502,7 @@ bool QDir::removeRecursively() di.next(); const QFileInfo& fi = di.fileInfo(); bool ok; - if (fi.isDir()) + if (fi.isDir() && !fi.isSymLink()) ok = QDir(di.filePath()).removeRecursively(); // recursive else ok = QFile::remove(di.filePath()); diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h index e246f2f1aa..5b058272e7 100644 --- a/src/corelib/io/qdir.h +++ b/src/corelib/io/qdir.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qdir_p.h b/src/corelib/io/qdir_p.h index a34427a716..7865c1d5a3 100644 --- a/src/corelib/io/qdir_p.h +++ b/src/corelib/io/qdir_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index 0b02adb4b6..28aa4a0f59 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qdiriterator.h b/src/corelib/io/qdiriterator.h index 5ad8acb496..be03415372 100644 --- a/src/corelib/io/qdiriterator.h +++ b/src/corelib/io/qdiriterator.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index d5118525cf..95d842da42 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h index 554b2954e1..903ba13963 100644 --- a/src/corelib/io/qfile.h +++ b/src/corelib/io/qfile.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfile_p.h b/src/corelib/io/qfile_p.h index 3072f5bc9e..24013c3c3d 100644 --- a/src/corelib/io/qfile_p.h +++ b/src/corelib/io/qfile_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 1ea6c8d50a..226b5d3560 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h index ef4573132c..6d6da3527a 100644 --- a/src/corelib/io/qfileinfo.h +++ b/src/corelib/io/qfileinfo.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h index 23ea0225f5..64e644f29f 100644 --- a/src/corelib/io/qfileinfo_p.h +++ b/src/corelib/io/qfileinfo_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp index 72900ec033..ab10f30585 100644 --- a/src/corelib/io/qfilesystemengine.cpp +++ b/src/corelib/io/qfilesystemengine.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemengine_mac.cpp b/src/corelib/io/qfilesystemengine_mac.cpp index 0d1556522a..f5e61ff29f 100644 --- a/src/corelib/io/qfilesystemengine_mac.cpp +++ b/src/corelib/io/qfilesystemengine_mac.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h index bbd4c4c020..af32a1c575 100644 --- a/src/corelib/io/qfilesystemengine_p.h +++ b/src/corelib/io/qfilesystemengine_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemengine_symbian.cpp b/src/corelib/io/qfilesystemengine_symbian.cpp deleted file mode 100644 index c8c1dfdc84..0000000000 --- a/src/corelib/io/qfilesystemengine_symbian.cpp +++ /dev/null @@ -1,406 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qfilesystemengine_p.h" -#include "qfsfileengine.h" -#include <QtCore/private/qcore_symbian_p.h> -#include <QtCore/qcoreapplication.h> - -#include <f32file.h> -#include <pathinfo.h> -#include <wchar.h> - -QT_BEGIN_NAMESPACE - -bool QFileSystemEngine::isCaseSensitive() -{ - return false; -} - -//TODO: resolve this with QDir::cleanPath, without breaking the behaviour of that -//function which is documented only by autotest -//input: a dirty absolute path, e.g. c:/../../foo/./ -//output: a clean absolute path, e.g. c:/foo/ -static QString symbianCleanAbsolutePath(const QString& path) -{ - bool isDir = path.endsWith(QLatin1Char('/')); - //using SkipEmptyParts flag to eliminate duplicated slashes - QStringList components = path.split(QLatin1Char('/'), QString::SkipEmptyParts); - int cdups = 0; - for(int i=components.count() - 1; i>=0; --i) { - if(components.at(i) == QLatin1String("..")) { - components.removeAt(i); - cdups++; - } - else if(components.at(i) == QLatin1String(".")) { - components.removeAt(i); - } - else if(cdups && i > 0) { - --cdups; - components.removeAt(i); - } - } - QString result = components.join(QLatin1String("/")); - if ((isDir&& !result.endsWith(QLatin1Char('/'))) - || (result.length() == 2 && result.at(1).unicode() == ':')) - result.append(QLatin1Char('/')); - return result; -} - -//static -QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data) -{ - Q_UNUSED(data); - return link; -} - -//static -QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data) -{ - if (entry.isEmpty() || entry.isRoot()) - return entry; - - QFileSystemEntry result = absoluteName(entry); - if (!data.hasFlags(QFileSystemMetaData::ExistsAttribute)) - fillMetaData(result, data, QFileSystemMetaData::ExistsAttribute); - if (!data.exists()) { - // file doesn't exist - return QFileSystemEntry(); - } else { - return result; - } -} - -//static -QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry) -{ - QString orig = entry.filePath(); - const bool isAbsolute = entry.isAbsolute(); - const bool isDirty = !entry.isClean(); - if (isAbsolute && !isDirty) - return entry; - - const bool isRelative = entry.isRelative(); - const bool needsDrive = (!orig.isEmpty() && orig.at(0).unicode() == '/'); - const bool isDriveLetter = !needsDrive && !isAbsolute && !isRelative && orig.length() == 2; - const bool isDriveRelative = !needsDrive && !isAbsolute && !isRelative && orig.length() > 2; - - QString result; - if (needsDrive || isDriveLetter || isDriveRelative || !isAbsolute || orig.isEmpty()) { - QFileSystemEntry cur(currentPath()); - if(needsDrive) - result = cur.filePath().left(2); - else if(isDriveRelative && cur.filePath().at(0) != orig.at(0)) - result = orig.left(2); // for BC, see tst_QFileInfo::absolutePath(<not current drive>:my.dll) - else - result = cur.filePath(); - if(isDriveLetter) { - result[0] = orig.at(0); //copy drive letter - orig.clear(); - } - if(isDriveRelative) { - orig = orig.mid(2); //discard the drive specifier from orig - } - } - if (!orig.isEmpty() && !(orig.length() == 1 && orig.at(0).unicode() == '.')) { - if (!result.isEmpty() && !result.endsWith(QLatin1Char('/'))) - result.append(QLatin1Char('/')); - result.append(orig); - } - - return QFileSystemEntry(symbianCleanAbsolutePath(result), QFileSystemEntry::FromInternalPath()); -} - -void QFileSystemMetaData::fillFromTEntry(const TEntry& entry) -{ - entryFlags &= ~(QFileSystemMetaData::SymbianTEntryFlags); - knownFlagsMask |= QFileSystemMetaData::SymbianTEntryFlags; - //Symbian doesn't have unix type file permissions - entryFlags |= QFileSystemMetaData::ReadPermissions; - if(!entry.IsReadOnly()) { - entryFlags |= QFileSystemMetaData::WritePermissions; - } - //set the type - if(entry.IsDir()) - entryFlags |= (QFileSystemMetaData::DirectoryType | QFileSystemMetaData::ExecutePermissions); - else - entryFlags |= QFileSystemMetaData::FileType; - - //set the attributes - entryFlags |= QFileSystemMetaData::ExistsAttribute; - if(entry.IsHidden()) - entryFlags |= QFileSystemMetaData::HiddenAttribute; - -#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API - size_ = entry.FileSize(); -#else - size_ = (TUint)(entry.iSize); -#endif - - modificationTime_ = entry.iModified; -} - -void QFileSystemMetaData::fillFromVolumeInfo(const TVolumeInfo& info) -{ - entryFlags &= ~(QFileSystemMetaData::SymbianTEntryFlags); - knownFlagsMask |= QFileSystemMetaData::SymbianTEntryFlags; - entryFlags |= QFileSystemMetaData::ExistsAttribute; - entryFlags |= QFileSystemMetaData::Permissions; - if(info.iDrive.iDriveAtt & KDriveAttRom) { - entryFlags &= ~(QFileSystemMetaData::WritePermissions); - } - entryFlags |= QFileSystemMetaData::DirectoryType; - size_ = info.iSize; - modificationTime_ = qt_symbian_time_t_To_TTime(0); -} - -//static -bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, QFileSystemMetaData::MetaDataFlags what) -{ - if (what & QFileSystemMetaData::SymbianTEntryFlags) { - RFs& fs(qt_s60GetRFs()); - TInt err; - QFileSystemEntry absentry(absoluteName(entry)); - if (entry.isEmpty()) { - err = KErrNotFound; - } else if (absentry.isRoot()) { - //Root directories don't have an entry, and Entry() returns KErrBadName. - //Therefore get information about the volume instead. - TInt drive; - err = RFs::CharToDrive(TChar(absentry.nativeFilePath().at(0).unicode()), drive); - if (!err) { - TVolumeInfo info; - err = fs.Volume(info, drive); - if (!err) - data.fillFromVolumeInfo(info); - } - } else { - TEntry ent; - err = fs.Entry(qt_QString2TPtrC(absentry.nativeFilePath()), ent); - if (!err) - data.fillFromTEntry(ent); - } - if (err) { - data.size_ = 0; - data.modificationTime_ = TTime(0); - data.entryFlags &= ~(QFileSystemMetaData::SymbianTEntryFlags); - } - //files in /sys/bin on any drive are executable, even though we don't normally have permission to check whether they exist or not - if(absentry.filePath().midRef(1,10).compare(QLatin1String(":/sys/bin/"), Qt::CaseInsensitive) == 0) - data.entryFlags |= QFileSystemMetaData::ExecutePermissions; - } - return data.hasFlags(what); -} - -//static -bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents) -{ - QString abspath = absoluteName(entry).nativeFilePath(); - if (!abspath.endsWith(QLatin1Char('\\'))) - abspath.append(QLatin1Char('\\')); - TInt r; - if (createParents) - r = qt_s60GetRFs().MkDirAll(qt_QString2TPtrC(abspath)); - else - r = qt_s60GetRFs().MkDir(qt_QString2TPtrC(abspath)); - if (createParents && r == KErrAlreadyExists) - return true; //# Qt5 - QDir::mkdir returns false for existing dir, QDir::mkpath returns true (should be made consistent in Qt 5) - return (r == KErrNone); -} - -//static -bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents) -{ - QString abspath = absoluteName(entry).nativeFilePath(); - if (!abspath.endsWith(QLatin1Char('\\'))) - abspath.append(QLatin1Char('\\')); - TPtrC dir(qt_QString2TPtrC(abspath)); - RFs& fs = qt_s60GetRFs(); - bool ok = false; - //behaviour of FS file engine: - //returns true if the directory could be removed - //success/failure of removing parent directories does not matter - while (KErrNone == fs.RmDir(dir)) { - ok = true; - if (!removeEmptyParents) - break; - //RFs::RmDir treats "c:\foo\bar" and "c:\foo\" the same, so it is sufficient to remove the last \ to the end - dir.Set(dir.Left(dir.LocateReverse(TChar('\\')))); - } - return ok; -} - -//static -bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) -{ - Q_UNUSED(source) - Q_UNUSED(target) - error = QSystemError(KErrNotSupported, QSystemError::NativeError); - return false; -} - -//static -bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) -{ - //CFileMan is allocated each time because it is not thread-safe - CFileMan *fm = 0; - TRAPD(err, fm = CFileMan::NewL(qt_s60GetRFs())); - if (err == KErrNone) { - err = fm->Copy(qt_QString2TPtrC(absoluteName(source).nativeFilePath()), qt_QString2TPtrC(absoluteName(target).nativeFilePath()), 0); - delete fm; - } - if (err == KErrNone) - return true; - error = QSystemError(err, QSystemError::NativeError); - return false; -} - -//static -bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) -{ - QString sourcepath = absoluteName(source).nativeFilePath(); - QString targetpath = absoluteName(target).nativeFilePath(); - RFs& fs(qt_s60GetRFs()); - TInt err = fs.Rename(qt_QString2TPtrC(sourcepath), qt_QString2TPtrC(targetpath)); - if (err == KErrNone) - return true; - error = QSystemError(err, QSystemError::NativeError); - return false; -} - -//static -bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error) -{ - QString targetpath = absoluteName(entry).nativeFilePath(); - RFs& fs(qt_s60GetRFs()); - TInt err = fs.Delete(qt_QString2TPtrC(targetpath)); - if (err == KErrNone) - return true; - error = QSystemError(err, QSystemError::NativeError); - return false; -} - -//static -bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data) -{ - QString targetpath = absoluteName(entry).nativeFilePath(); - TUint setmask = 0; - TUint clearmask = 0; - RFs& fs(qt_s60GetRFs()); - if (permissions & (QFile::WriteOwner | QFile::WriteUser | QFile::WriteGroup | QFile::WriteOther)) - clearmask = KEntryAttReadOnly; //if anyone can write, it's not read-only - else - setmask = KEntryAttReadOnly; - TInt err = fs.SetAtt(qt_QString2TPtrC(targetpath), setmask, clearmask); - if (data && !err) { - data->entryFlags &= ~QFileSystemMetaData::Permissions; - data->entryFlags |= QFileSystemMetaData::MetaDataFlag(uint(permissions)); - data->knownFlagsMask |= QFileSystemMetaData::Permissions; - } - if (err == KErrNone) - return true; - error = QSystemError(err, QSystemError::NativeError); - return false; -} - -QString QFileSystemEngine::homePath() -{ - QString home = QDir::fromNativeSeparators(qt_TDesC2QString(PathInfo::PhoneMemoryRootPath())); - if(home.endsWith(QLatin1Char('/'))) - home.chop(1); - return home; -} - -QString QFileSystemEngine::rootPath() -{ - TChar drive; - TInt err = RFs::DriveToChar(RFs::GetSystemDrive(), drive); //RFs::GetSystemDriveChar not supported on S60 3.1 - Q_ASSERT(err == KErrNone); //RFs::GetSystemDrive() shall always return a convertible drive number on a valid OS configuration - return QString(QChar(drive)).append(QLatin1String(":/")); -} - -QString QFileSystemEngine::tempPath() -{ - return rootPath().append(QLatin1String("system/temp")); -} - -//static -bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry) -{ - QFileSystemMetaData meta; - QFileSystemEntry absname = absoluteName(entry); - fillMetaData(absname, meta, QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType); - if(!(meta.exists() && meta.isDirectory())) - return false; - - RFs& fs = qt_s60GetRFs(); - QString abspath = absname.nativeFilePath(); - if(!abspath.endsWith(QLatin1Char('\\'))) - abspath.append(QLatin1Char('\\')); - TInt r = fs.SetSessionPath(qt_QString2TPtrC(abspath)); - //SetSessionPath succeeds for non existent directory, which is why it's checked above - if (r == KErrNone) { - __ASSERT_COMPILE(sizeof(wchar_t) == sizeof(unsigned short)); - //attempt to set open C to the same path - r = ::wchdir(reinterpret_cast<const wchar_t *>(absname.filePath().utf16())); - if (r < 0) - qWarning("failed to sync path to open C"); - return true; - } - return false; -} - -//static -QFileSystemEntry QFileSystemEngine::currentPath() -{ - TFileName fn; - QFileSystemEntry ret; - TInt r = qt_s60GetRFs().SessionPath(fn); - if(r == KErrNone) { - //remove terminating slash from non root paths (session path is clean, absolute and always ends in a \) - if(fn.Length() > 3 && fn[fn.Length() - 1] == '\\') - fn.SetLength(fn.Length() - 1); - ret = QFileSystemEntry(qt_TDesC2QString(fn), QFileSystemEntry::FromNativePath()); - } - return ret; -} - -QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 9778b526ac..901aaf8f91 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 10ba95e97f..d724429f6b 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -160,6 +160,31 @@ typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACC static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0; static TRUSTEE_W currentUserTrusteeW; static TRUSTEE_W worldTrusteeW; +static PSID currentUserSID = 0; +static PSID worldSID = 0; + +/* + Deletes the allocated SIDs during global static cleanup +*/ +class SidCleanup +{ +public: + ~SidCleanup(); +}; + +SidCleanup::~SidCleanup() +{ + qFree(currentUserSID); + currentUserSID = 0; + + // worldSID was allocated with AllocateAndInitializeSid so it needs to be freed with FreeSid + if (worldSID) { + ::FreeSid(worldSID); + worldSID = 0; + } +} + +Q_GLOBAL_STATIC(SidCleanup, initSidCleanup) typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD); static PtrGetUserProfileDirectoryW ptrGetUserProfileDirectoryW = 0; @@ -199,25 +224,35 @@ static void resolveLibs() // Create TRUSTEE for current user HANDLE hnd = ::GetCurrentProcess(); HANDLE token = 0; + initSidCleanup(); if (::OpenProcessToken(hnd, TOKEN_QUERY, &token)) { - TOKEN_USER tu; - DWORD retsize; - if (::GetTokenInformation(token, TokenUser, &tu, sizeof(tu), &retsize)) - ptrBuildTrusteeWithSidW(¤tUserTrusteeW, tu.User.Sid); + DWORD retsize = 0; + // GetTokenInformation requires a buffer big enough for the TOKEN_USER struct and + // the SID struct. Since the SID struct can have variable number of subauthorities + // tacked at the end, its size is variable. Obtain the required size by first + // doing a dummy GetTokenInformation call. + ::GetTokenInformation(token, TokenUser, 0, 0, &retsize); + if (retsize) { + void *tokenBuffer = qMalloc(retsize); + if (::GetTokenInformation(token, TokenUser, tokenBuffer, retsize, &retsize)) { + PSID tokenSid = reinterpret_cast<PTOKEN_USER>(tokenBuffer)->User.Sid; + DWORD sidLen = ::GetLengthSid(tokenSid); + currentUserSID = reinterpret_cast<PSID>(qMalloc(sidLen)); + if (::CopySid(sidLen, currentUserSID, tokenSid)) + ptrBuildTrusteeWithSidW(¤tUserTrusteeW, currentUserSID); + } + qFree(tokenBuffer); + } ::CloseHandle(token); } typedef BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*); PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = (PtrAllocateAndInitializeSid)GetProcAddress(advapiHnd, "AllocateAndInitializeSid"); - typedef PVOID (WINAPI *PtrFreeSid)(PSID); - PtrFreeSid ptrFreeSid = (PtrFreeSid)GetProcAddress(advapiHnd, "FreeSid"); - if (ptrAllocateAndInitializeSid && ptrFreeSid) { + if (ptrAllocateAndInitializeSid) { // Create TRUSTEE for Everyone (World) SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY }; - PSID pWorld = 0; - if (ptrAllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pWorld)) - ptrBuildTrusteeWithSidW(&worldTrusteeW, pWorld); - ptrFreeSid(pWorld); + if (ptrAllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldSID)) + ptrBuildTrusteeWithSidW(&worldTrusteeW, worldSID); } } HINSTANCE userenvHnd = QSystemLibrary::load(L"userenv"); @@ -278,7 +313,7 @@ static QString readSymLink(const QFileSystemEntry &link) 0); if (handle != INVALID_HANDLE_VALUE) { DWORD bufsize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; - REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)qMalloc(bufsize); + REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)malloc(bufsize); DWORD retsize = 0; if (::DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, 0, 0, rdb, bufsize, &retsize, 0)) { if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { @@ -296,7 +331,7 @@ static QString readSymLink(const QFileSystemEntry &link) if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\')) result = result.mid(4); } - qFree(rdb); + free(rdb); CloseHandle(handle); #if !defined(QT_NO_LIBRARY) diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp index 2f37542f66..11b73dd745 100644 --- a/src/corelib/io/qfilesystementry.cpp +++ b/src/corelib/io/qfilesystementry.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystementry_p.h b/src/corelib/io/qfilesystementry_p.h index 8d524c087e..61902f77d0 100644 --- a/src/corelib/io/qfilesystementry_p.h +++ b/src/corelib/io/qfilesystementry_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemiterator_p.h b/src/corelib/io/qfilesystemiterator_p.h index 6f2d1e1c6e..7df5988459 100644 --- a/src/corelib/io/qfilesystemiterator_p.h +++ b/src/corelib/io/qfilesystemiterator_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemiterator_symbian.cpp b/src/corelib/io/qfilesystemiterator_symbian.cpp deleted file mode 100644 index 4347f6acba..0000000000 --- a/src/corelib/io/qfilesystemiterator_symbian.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qfilesystemiterator_p.h" -#include "qfilesystemengine_p.h" -#include <QtCore/private/qcore_symbian_p.h> - -QT_BEGIN_NAMESPACE - -QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &path, QDir::Filters filters, - const QStringList &nameFilters, QDirIterator::IteratorFlags iteratorFlags) - : lastError(KErrNone), entryIndex(-1) -{ - RFs& fs = qt_s60GetRFs(); - - nativePath = path.nativeFilePath(); - if (!nativePath.endsWith(QLatin1Char('\\'))) - nativePath.append(QLatin1Char('\\')); - - QString absPath = QFileSystemEngine::absoluteName(path).nativeFilePath(); - - if (!absPath.endsWith(QLatin1Char('\\'))) - absPath.append(QLatin1Char('\\')); - - int pathLen = absPath.length(); - if (pathLen > KMaxFileName) { - lastError = KErrBadName; - return; - } - - //set up server side filtering to reduce IPCs - //RDir won't accept all valid name filters e.g. "*. bar" - if (nameFilters.count() == 1 && !(filters & QDir::AllDirs) && iteratorFlags - == QDirIterator::NoIteratorFlags && pathLen + nameFilters[0].length() - <= KMaxFileName) { - //server side supports one mask - skip this for recursive mode or if only files should be filtered - absPath.append(nameFilters[0]); - } - - TUint symbianMask = 0; - if ((filters & QDir::Dirs) || (filters & QDir::AllDirs) || (iteratorFlags - & QDirIterator::Subdirectories)) - symbianMask |= KEntryAttDir; //include directories - if (filters & QDir::Hidden) - symbianMask |= KEntryAttHidden; - if (filters & QDir::System) - symbianMask |= KEntryAttSystem; - if (((filters & QDir::Files) == 0) && symbianMask == KEntryAttDir) - symbianMask |= KEntryAttMatchExclusive; //exclude non-directories - else if (symbianMask == 0) { - if ((filters & QDir::PermissionMask) == QDir::Writable) - symbianMask = KEntryAttMatchExclude | KEntryAttReadOnly; - } - - lastError = dirHandle.Open(fs, qt_QString2TPtrC(absPath), symbianMask); -} - -QFileSystemIterator::~QFileSystemIterator() -{ - dirHandle.Close(); -} - -bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData) -{ - //1st time, lastError is result of dirHandle.Open(), entries.Count() is 0 and entryIndex is -1 so initial read is triggered - //subsequent times, read is triggered each time we reach the end of the entry list - //final time, lastError is KErrEof so we don't need to read anymore. - ++entryIndex; - if (lastError == KErrNone && entryIndex >= entries.Count()) { - lastError = dirHandle.Read(entries); - entryIndex = 0; - } - - //each call to advance() gets the next entry from the entry list. - //from the final (or only) read call, KErrEof is returned together with a full buffer so we still need to go through the list - if ((lastError == KErrNone || lastError == KErrEof) && entryIndex < entries.Count()) { - Q_ASSERT(entryIndex >= 0); - const TEntry &entry(entries[entryIndex]); - fileEntry = QFileSystemEntry(nativePath + qt_TDesC2QString(entry.iName), QFileSystemEntry::FromNativePath()); - metaData.fillFromTEntry(entry); - return true; - } - - //TODO: error reporting, to allow user to distinguish empty directory from error condition. - - return false; -} - -QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp index 6987660ea3..d0eb04a145 100644 --- a/src/corelib/io/qfilesystemiterator_unix.cpp +++ b/src/corelib/io/qfilesystemiterator_unix.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp index 5fff4f82c6..1f5cf356a0 100644 --- a/src/corelib/io/qfilesystemiterator_win.cpp +++ b/src/corelib/io/qfilesystemiterator_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h index 64749e3889..6ed5cec954 100644 --- a/src/corelib/io/qfilesystemmetadata_p.h +++ b/src/corelib/io/qfilesystemmetadata_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index 9739067c06..4abb4f3cc1 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -48,234 +48,45 @@ #include <qdebug.h> #include <qdir.h> #include <qfileinfo.h> -#include <qmutex.h> #include <qset.h> #include <qtimer.h> + +#include "qfilesystemwatcher_polling_p.h" #if defined(Q_OS_WIN) # include "qfilesystemwatcher_win_p.h" #elif defined(Q_OS_LINUX) # include "qfilesystemwatcher_inotify_p.h" -# include "qfilesystemwatcher_dnotify_p.h" #elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC) -# if (defined Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) -# include "qfilesystemwatcher_fsevents_p.h" -# endif //MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) # include "qfilesystemwatcher_kqueue_p.h" -#elif defined(Q_OS_SYMBIAN) -# include "qfilesystemwatcher_symbian_p.h" #endif QT_BEGIN_NAMESPACE -enum { PollingInterval = 1000 }; - -class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine -{ - Q_OBJECT - - class FileInfo - { - uint ownerId; - uint groupId; - QFile::Permissions permissions; - QDateTime lastModified; - QStringList entries; - - public: - FileInfo(const QFileInfo &fileInfo) - : ownerId(fileInfo.ownerId()), - groupId(fileInfo.groupId()), - permissions(fileInfo.permissions()), - lastModified(fileInfo.lastModified()) - { - if (fileInfo.isDir()) { - entries = fileInfo.absoluteDir().entryList(QDir::AllEntries); - } - } - FileInfo &operator=(const QFileInfo &fileInfo) - { - *this = FileInfo(fileInfo); - return *this; - } - - bool operator!=(const QFileInfo &fileInfo) const - { - if (fileInfo.isDir() && entries != fileInfo.absoluteDir().entryList(QDir::AllEntries)) - return true; - return (ownerId != fileInfo.ownerId() - || groupId != fileInfo.groupId() - || permissions != fileInfo.permissions() - || lastModified != fileInfo.lastModified()); - } - }; - - mutable QMutex mutex; - QHash<QString, FileInfo> files, directories; - -public: - QPollingFileSystemWatcherEngine(); - - void run(); - - QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); - QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); - - void stop(); - -private Q_SLOTS: - void timeout(); -}; - -QPollingFileSystemWatcherEngine::QPollingFileSystemWatcherEngine() -{ -#ifndef QT_NO_THREAD - moveToThread(this); -#endif -} - -void QPollingFileSystemWatcherEngine::run() -{ - QTimer timer; - connect(&timer, SIGNAL(timeout()), SLOT(timeout())); - timer.start(PollingInterval); - (void) exec(); -} - -QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths, - QStringList *files, - QStringList *directories) -{ - QMutexLocker locker(&mutex); - QStringList p = paths; - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - QFileInfo fi(path); - if (!fi.exists()) - continue; - if (fi.isDir()) { - if (!directories->contains(path)) - directories->append(path); - if (!path.endsWith(QLatin1Char('/'))) - fi = QFileInfo(path + QLatin1Char('/')); - this->directories.insert(path, fi); - } else { - if (!files->contains(path)) - files->append(path); - this->files.insert(path, fi); - } - it.remove(); - } - start(); - return p; -} - -QStringList QPollingFileSystemWatcherEngine::removePaths(const QStringList &paths, - QStringList *files, - QStringList *directories) -{ - QMutexLocker locker(&mutex); - QStringList p = paths; - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - if (this->directories.remove(path)) { - directories->removeAll(path); - it.remove(); - } else if (this->files.remove(path)) { - files->removeAll(path); - it.remove(); - } - } - if (this->files.isEmpty() && this->directories.isEmpty()) { - locker.unlock(); - stop(); - wait(); - } - return p; -} - -void QPollingFileSystemWatcherEngine::stop() -{ - quit(); -} - -void QPollingFileSystemWatcherEngine::timeout() -{ - QMutexLocker locker(&mutex); - QMutableHashIterator<QString, FileInfo> fit(files); - while (fit.hasNext()) { - QHash<QString, FileInfo>::iterator x = fit.next(); - QString path = x.key(); - QFileInfo fi(path); - if (!fi.exists()) { - fit.remove(); - emit fileChanged(path, true); - } else if (x.value() != fi) { - x.value() = fi; - emit fileChanged(path, false); - } - } - QMutableHashIterator<QString, FileInfo> dit(directories); - while (dit.hasNext()) { - QHash<QString, FileInfo>::iterator x = dit.next(); - QString path = x.key(); - QFileInfo fi(path); - if (!path.endsWith(QLatin1Char('/'))) - fi = QFileInfo(path + QLatin1Char('/')); - if (!fi.exists()) { - dit.remove(); - emit directoryChanged(path, true); - } else if (x.value() != fi) { - fi.refresh(); - if (!fi.exists()) { - dit.remove(); - emit directoryChanged(path, true); - } else { - x.value() = fi; - emit directoryChanged(path, false); - } - } - - } -} - - - - -QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine() +QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject *parent) { #if defined(Q_OS_WIN) - return new QWindowsFileSystemWatcherEngine; + return new QWindowsFileSystemWatcherEngine(parent); #elif defined(Q_OS_LINUX) - QFileSystemWatcherEngine *eng = QInotifyFileSystemWatcherEngine::create(); - if(!eng) - eng = QDnotifyFileSystemWatcherEngine::create(); - return eng; + // there is a chance that inotify may fail on Linux pre-2.6.13 (August + // 2005), so we can't just new inotify directly. + return QInotifyFileSystemWatcherEngine::create(parent); #elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC) -# if 0 && defined(Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) - return QFSEventsFileSystemWatcherEngine::create(); - else -# endif - return QKqueueFileSystemWatcherEngine::create(); -#elif defined(Q_OS_SYMBIAN) - return new QSymbianFileSystemWatcherEngine; + return QKqueueFileSystemWatcherEngine::create(parent); #else return 0; #endif } QFileSystemWatcherPrivate::QFileSystemWatcherPrivate() - : native(0), poller(0), forced(0) + : native(0), poller(0) { } void QFileSystemWatcherPrivate::init() { Q_Q(QFileSystemWatcher); - native = createNativeEngine(); + native = createNativeEngine(q); if (native) { QObject::connect(native, SIGNAL(fileChanged(QString,bool)), @@ -288,42 +99,13 @@ void QFileSystemWatcherPrivate::init() } } -void QFileSystemWatcherPrivate::initForcedEngine(const QString &forceName) -{ - if(forced) - return; - - Q_Q(QFileSystemWatcher); - -#if defined(Q_OS_LINUX) - if(forceName == QLatin1String("inotify")) { - forced = QInotifyFileSystemWatcherEngine::create(); - } else if(forceName == QLatin1String("dnotify")) { - forced = QDnotifyFileSystemWatcherEngine::create(); - } -#else - Q_UNUSED(forceName); -#endif - - if(forced) { - QObject::connect(forced, - SIGNAL(fileChanged(QString,bool)), - q, - SLOT(_q_fileChanged(QString,bool))); - QObject::connect(forced, - SIGNAL(directoryChanged(QString,bool)), - q, - SLOT(_q_directoryChanged(QString,bool))); - } -} - void QFileSystemWatcherPrivate::initPollerEngine() { if(poller) return; Q_Q(QFileSystemWatcher); - poller = new QPollingFileSystemWatcherEngine; // that was a mouthful + poller = new QPollingFileSystemWatcherEngine(q); // that was a mouthful QObject::connect(poller, SIGNAL(fileChanged(QString,bool)), q, @@ -434,27 +216,7 @@ QFileSystemWatcher::QFileSystemWatcher(const QStringList &paths, QObject *parent Destroys the file system watcher. */ QFileSystemWatcher::~QFileSystemWatcher() -{ - Q_D(QFileSystemWatcher); - if (d->native) { - d->native->stop(); - d->native->wait(); - delete d->native; - d->native = 0; - } - if (d->poller) { - d->poller->stop(); - d->poller->wait(); - delete d->poller; - d->poller = 0; - } - if (d->forced) { - d->forced->stop(); - d->forced->wait(); - delete d->forced; - d->forced = 0; - } -} +{ } /*! Adds \a path to the file system watcher if \a path exists. The @@ -466,20 +228,28 @@ QFileSystemWatcher::~QFileSystemWatcher() otherwise the fileChanged() signal is emitted when \a path is modified, renamed or removed. - \note There is a system dependent limit to the number of files and - directories that can be monitored simultaneously. If this limit - has been reached, \a path will not be added to the file system - watcher, and a warning message will be printed to \e{stderr}. + If the watch was successful, true is returned. + + Reasons for a watch failure are generally system-dependent, but + may include the resource not existing, access failures, or the + total watch count limit, if the platform has one. + + \note There may be a system dependent limit to the number of + files and directories that can be monitored simultaneously. + If this limit is been reached, \a path will not be monitored, + and false is returned. \sa addPaths(), removePath() */ -void QFileSystemWatcher::addPath(const QString &path) +bool QFileSystemWatcher::addPath(const QString &path) { if (path.isEmpty()) { qWarning("QFileSystemWatcher::addPath: path is empty"); - return; + return true; } - addPaths(QStringList(path)); + + QStringList paths = addPaths(QStringList(path)); + return paths.isEmpty(); } /*! @@ -492,23 +262,37 @@ void QFileSystemWatcher::addPath(const QString &path) otherwise the fileChanged() signal is emitted when the path is modified, renamed, or removed. - \note There is a system dependent limit to the number of files and - directories that can be monitored simultaneously. If this limit - has been reached, the excess \a paths will not be added to the - file system watcher, and a warning message will be printed to - \e{stderr} for each path that could not be added. + The return value is a list of paths that could not be watched. + + Reasons for a watch failure are generally system-dependent, but + may include the resource not existing, access failures, or the + total watch count limit, if the platform has one. + + \note There may be a system dependent limit to the number of + files and directories that can be monitored simultaneously. + If this limit has been reached, the excess \a paths will not + be monitored, and they will be added to the returned QStringList. \sa addPath(), removePaths() */ -void QFileSystemWatcher::addPaths(const QStringList &paths) +QStringList QFileSystemWatcher::addPaths(const QStringList &paths) { Q_D(QFileSystemWatcher); - if (paths.isEmpty()) { + + QStringList p = paths; + QMutableListIterator<QString> it(p); + + while (it.hasNext()) { + const QString &path = it.next(); + if (path.isEmpty()) + it.remove(); + } + + if (p.isEmpty()) { qWarning("QFileSystemWatcher::addPaths: list is empty"); - return; + return QStringList(); } - QStringList p = paths; QFileSystemWatcherEngine *engine = 0; if(!objectName().startsWith(QLatin1String("_qt_autotest_force_engine_"))) { @@ -530,54 +314,71 @@ void QFileSystemWatcher::addPaths(const QStringList &paths) } else if(forceName == QLatin1String("native")) { qDebug() << "QFileSystemWatcher: skipping polling engine, using only native engine"; engine = d->native; - } else { - qDebug() << "QFileSystemWatcher: skipping polling and native engine, using only explicit" << forceName << "engine"; - d_func()->initForcedEngine(forceName); - engine = d->forced; } } if(engine) p = engine->addPaths(p, &d->files, &d->directories); - if (!p.isEmpty()) - qWarning("QFileSystemWatcher: failed to add paths: %s", - qPrintable(p.join(QLatin1String(", ")))); + return p; } /*! Removes the specified \a path from the file system watcher. + If the watch is successfully removed, true is returned. + + Reasons for watch removal failing are generally system-dependent, + but may be due to the path having already been deleted, for example. + \sa removePaths(), addPath() */ -void QFileSystemWatcher::removePath(const QString &path) +bool QFileSystemWatcher::removePath(const QString &path) { if (path.isEmpty()) { qWarning("QFileSystemWatcher::removePath: path is empty"); - return; + return true; } - removePaths(QStringList(path)); + + QStringList paths = removePaths(QStringList(path)); + return paths.isEmpty(); } /*! Removes the specified \a paths from the file system watcher. + The return value is a list of paths which were not able to be + unwatched successfully. + + Reasons for watch removal failing are generally system-dependent, + but may be due to the path having already been deleted, for example. + \sa removePath(), addPaths() */ -void QFileSystemWatcher::removePaths(const QStringList &paths) +QStringList QFileSystemWatcher::removePaths(const QStringList &paths) { - if (paths.isEmpty()) { - qWarning("QFileSystemWatcher::removePaths: list is empty"); - return; - } Q_D(QFileSystemWatcher); + QStringList p = paths; + QMutableListIterator<QString> it(p); + + while (it.hasNext()) { + const QString &path = it.next(); + if (path.isEmpty()) + it.remove(); + } + + if (p.isEmpty()) { + qWarning("QFileSystemWatcher::removePaths: list is empty"); + return QStringList(); + } + if (d->native) p = d->native->removePaths(p, &d->files, &d->directories); if (d->poller) p = d->poller->removePaths(p, &d->files, &d->directories); - if (d->forced) - p = d->forced->removePaths(p, &d->files, &d->directories); + + return p; } /*! @@ -634,7 +435,5 @@ QT_END_NAMESPACE #include "moc_qfilesystemwatcher.cpp" -#include "qfilesystemwatcher.moc" - #endif // QT_NO_FILESYSTEMWATCHER diff --git a/src/corelib/io/qfilesystemwatcher.h b/src/corelib/io/qfilesystemwatcher.h index 763c8de0d6..7b7dbe98c5 100644 --- a/src/corelib/io/qfilesystemwatcher.h +++ b/src/corelib/io/qfilesystemwatcher.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -64,10 +64,10 @@ public: QFileSystemWatcher(const QStringList &paths, QObject *parent = 0); ~QFileSystemWatcher(); - void addPath(const QString &file); - void addPaths(const QStringList &files); - void removePath(const QString &file); - void removePaths(const QStringList &files); + bool addPath(const QString &file); + QStringList addPaths(const QStringList &files); + bool removePath(const QString &file); + QStringList removePaths(const QStringList &files); QStringList files() const; QStringList directories() const; diff --git a/src/corelib/io/qfilesystemwatcher_dnotify.cpp b/src/corelib/io/qfilesystemwatcher_dnotify.cpp deleted file mode 100644 index 46c3b46467..0000000000 --- a/src/corelib/io/qfilesystemwatcher_dnotify.cpp +++ /dev/null @@ -1,461 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qplatformdefs.h" -#include "qfilesystemwatcher.h" -#include "qfilesystemwatcher_dnotify_p.h" - -#ifndef QT_NO_FILESYSTEMWATCHER - -#include <qsocketnotifier.h> -#include <qcoreapplication.h> -#include <qfileinfo.h> -#include <qtimer.h> -#include <qwaitcondition.h> -#include <qmutex.h> -#include <dirent.h> -#include <qdir.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <signal.h> -#include <unistd.h> -#include <fcntl.h> -#include <time.h> - -#include "private/qcore_unix_p.h" - -#ifdef QT_LINUXBASE - -/* LSB doesn't standardize these */ -#define F_NOTIFY 1026 -#define DN_ACCESS 0x00000001 -#define DN_MODIFY 0x00000002 -#define DN_CREATE 0x00000004 -#define DN_DELETE 0x00000008 -#define DN_RENAME 0x00000010 -#define DN_ATTRIB 0x00000020 -#define DN_MULTISHOT 0x80000000 - -#endif - -QT_BEGIN_NAMESPACE - -static int qfswd_fileChanged_pipe[2]; -static void (*qfswd_old_sigio_handler)(int) = 0; -static void (*qfswd_old_sigio_action)(int, siginfo_t *, void *) = 0; -static void qfswd_sigio_monitor(int signum, siginfo_t *i, void *v) -{ - qt_safe_write(qfswd_fileChanged_pipe[1], reinterpret_cast<char*>(&i->si_fd), sizeof(int)); - - if (qfswd_old_sigio_handler && qfswd_old_sigio_handler != SIG_IGN) - qfswd_old_sigio_handler(signum); - if (qfswd_old_sigio_action) - qfswd_old_sigio_action(signum, i, v); -} - -class QDnotifySignalThread : public QThread -{ -Q_OBJECT -public: - QDnotifySignalThread(); - virtual ~QDnotifySignalThread(); - - void startNotify(); - - virtual void run(); - -signals: - void fdChanged(int); - -protected: - virtual bool event(QEvent *); - -private slots: - void readFromDnotify(); - -private: - QMutex mutex; - QWaitCondition wait; - bool isExecing; -}; - -Q_GLOBAL_STATIC(QDnotifySignalThread, dnotifySignal) - -QDnotifySignalThread::QDnotifySignalThread() -: isExecing(false) -{ - moveToThread(this); - - qt_safe_pipe(qfswd_fileChanged_pipe, O_NONBLOCK); - - struct sigaction oldAction; - struct sigaction action; - memset(&action, 0, sizeof(action)); - action.sa_sigaction = qfswd_sigio_monitor; - action.sa_flags = SA_SIGINFO; - ::sigaction(SIGIO, &action, &oldAction); - if (!(oldAction.sa_flags & SA_SIGINFO)) - qfswd_old_sigio_handler = oldAction.sa_handler; - else - qfswd_old_sigio_action = oldAction.sa_sigaction; -} - -QDnotifySignalThread::~QDnotifySignalThread() -{ - if(isRunning()) { - quit(); - QThread::wait(); - } -} - -bool QDnotifySignalThread::event(QEvent *e) -{ - if(e->type() == QEvent::User) { - QMutexLocker locker(&mutex); - isExecing = true; - wait.wakeAll(); - return true; - } else { - return QThread::event(e); - } -} - -void QDnotifySignalThread::startNotify() -{ - // Note: All this fancy waiting for the thread to enter its event - // loop is to avoid nasty messages at app shutdown when the - // QDnotifySignalThread singleton is deleted - start(); - mutex.lock(); - while(!isExecing) - wait.wait(&mutex); - mutex.unlock(); -} - -void QDnotifySignalThread::run() -{ - QSocketNotifier sn(qfswd_fileChanged_pipe[0], QSocketNotifier::Read, this); - connect(&sn, SIGNAL(activated(int)), SLOT(readFromDnotify())); - - QCoreApplication::instance()->postEvent(this, new QEvent(QEvent::User)); - (void) exec(); -} - -void QDnotifySignalThread::readFromDnotify() -{ - int fd; - int readrv = qt_safe_read(qfswd_fileChanged_pipe[0], reinterpret_cast<char*>(&fd), sizeof(int)); - // Only expect EAGAIN or EINTR. Other errors are assumed to be impossible. - if(readrv != -1) { - Q_ASSERT(readrv == sizeof(int)); - Q_UNUSED(readrv); - - if(0 == fd) - quit(); - else - emit fdChanged(fd); - } -} - -QDnotifyFileSystemWatcherEngine::QDnotifyFileSystemWatcherEngine() -{ - QObject::connect(dnotifySignal(), SIGNAL(fdChanged(int)), - this, SLOT(refresh(int)), Qt::DirectConnection); -} - -QDnotifyFileSystemWatcherEngine::~QDnotifyFileSystemWatcherEngine() -{ - QMutexLocker locker(&mutex); - - for(QHash<int, Directory>::ConstIterator iter = fdToDirectory.constBegin(); - iter != fdToDirectory.constEnd(); - ++iter) { - qt_safe_close(iter->fd); - if(iter->parentFd) - qt_safe_close(iter->parentFd); - } -} - -QDnotifyFileSystemWatcherEngine *QDnotifyFileSystemWatcherEngine::create() -{ - return new QDnotifyFileSystemWatcherEngine(); -} - -void QDnotifyFileSystemWatcherEngine::run() -{ - qFatal("QDnotifyFileSystemWatcherEngine thread should not be run"); -} - -QStringList QDnotifyFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *files, QStringList *directories) -{ - QMutexLocker locker(&mutex); - - QStringList p = paths; - QMutableListIterator<QString> it(p); - - while (it.hasNext()) { - QString path = it.next(); - - QFileInfo fi(path); - - if(!fi.exists()) { - continue; - } - - bool isDir = fi.isDir(); - - if (isDir && directories->contains(path)) { - continue; // Skip monitored directories - } else if(!isDir && files->contains(path)) { - continue; // Skip monitored files - } - - if(!isDir) - path = fi.canonicalPath(); - - // Locate the directory entry (creating if needed) - int fd = pathToFD[path]; - - if(fd == 0) { - - QT_DIR *d = QT_OPENDIR(path.toUtf8().constData()); - if(!d) continue; // Could not open directory - QT_DIR *parent = 0; - - QDir parentDir(path); - if(!parentDir.isRoot()) { - parentDir.cdUp(); - parent = QT_OPENDIR(parentDir.path().toUtf8().constData()); - if(!parent) { - QT_CLOSEDIR(d); - continue; - } - } - - fd = qt_safe_dup(::dirfd(d)); - int parentFd = parent ? qt_safe_dup(::dirfd(parent)) : 0; - - QT_CLOSEDIR(d); - if(parent) QT_CLOSEDIR(parent); - - Q_ASSERT(fd); - if(::fcntl(fd, F_SETSIG, SIGIO) || - ::fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_DELETE | - DN_RENAME | DN_ATTRIB | DN_MULTISHOT) || - (parent && ::fcntl(parentFd, F_SETSIG, SIGIO)) || - (parent && ::fcntl(parentFd, F_NOTIFY, DN_DELETE | DN_RENAME | - DN_MULTISHOT))) { - continue; // Could not set appropriate flags - } - - Directory dir; - dir.path = path; - dir.fd = fd; - dir.parentFd = parentFd; - - fdToDirectory.insert(fd, dir); - pathToFD.insert(path, fd); - if(parentFd) - parentToFD.insert(parentFd, fd); - } - - Directory &directory = fdToDirectory[fd]; - - if(isDir) { - directory.isMonitored = true; - } else { - Directory::File file; - file.path = fi.filePath(); - file.lastWrite = fi.lastModified(); - directory.files.append(file); - pathToFD.insert(fi.filePath(), fd); - } - - it.remove(); - - if(isDir) { - directories->append(path); - } else { - files->append(fi.filePath()); - } - } - - dnotifySignal()->startNotify(); - - return p; -} - -QStringList QDnotifyFileSystemWatcherEngine::removePaths(const QStringList &paths, QStringList *files, QStringList *directories) -{ - QMutexLocker locker(&mutex); - - QStringList p = paths; - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - - QString path = it.next(); - int fd = pathToFD.take(path); - - if(!fd) - continue; - - Directory &directory = fdToDirectory[fd]; - bool isDir = false; - if(directory.path == path) { - isDir = true; - directory.isMonitored = false; - } else { - for(int ii = 0; ii < directory.files.count(); ++ii) { - if(directory.files.at(ii).path == path) { - directory.files.removeAt(ii); - break; - } - } - } - - if(!directory.isMonitored && directory.files.isEmpty()) { - // No longer needed - qt_safe_close(directory.fd); - pathToFD.remove(directory.path); - fdToDirectory.remove(fd); - } - - if(isDir) { - directories->removeAll(path); - } else { - files->removeAll(path); - } - - it.remove(); - } - - return p; -} - -void QDnotifyFileSystemWatcherEngine::refresh(int fd) -{ - QMutexLocker locker(&mutex); - - bool wasParent = false; - QHash<int, Directory>::Iterator iter = fdToDirectory.find(fd); - if(iter == fdToDirectory.end()) { - QHash<int, int>::Iterator pIter = parentToFD.find(fd); - if(pIter == parentToFD.end()) - return; - - iter = fdToDirectory.find(*pIter); - if (iter == fdToDirectory.end()) - return; - wasParent = true; - } - - Directory &directory = *iter; - - if(!wasParent) { - for(int ii = 0; ii < directory.files.count(); ++ii) { - Directory::File &file = directory.files[ii]; - if(file.updateInfo()) { - // Emit signal - QString filePath = file.path; - bool removed = !QFileInfo(filePath).exists(); - - if(removed) { - directory.files.removeAt(ii); - --ii; - } - - emit fileChanged(filePath, removed); - } - } - } - - if(directory.isMonitored) { - // Emit signal - bool removed = !QFileInfo(directory.path).exists(); - QString path = directory.path; - - if(removed) - directory.isMonitored = false; - - emit directoryChanged(path, removed); - } - - if(!directory.isMonitored && directory.files.isEmpty()) { - qt_safe_close(directory.fd); - if(directory.parentFd) { - qt_safe_close(directory.parentFd); - parentToFD.remove(directory.parentFd); - } - fdToDirectory.erase(iter); - } -} - -void QDnotifyFileSystemWatcherEngine::stop() -{ -} - -bool QDnotifyFileSystemWatcherEngine::Directory::File::updateInfo() -{ - QFileInfo fi(path); - QDateTime nLastWrite = fi.lastModified(); - uint nOwnerId = fi.ownerId(); - uint nGroupId = fi.groupId(); - QFile::Permissions nPermissions = fi.permissions(); - - if(nLastWrite != lastWrite || - nOwnerId != ownerId || - nGroupId != groupId || - nPermissions != permissions) { - ownerId = nOwnerId; - groupId = nGroupId; - permissions = nPermissions; - lastWrite = nLastWrite; - return true; - } else { - return false; - } -} - -QT_END_NAMESPACE - -#include "qfilesystemwatcher_dnotify.moc" - -#endif // QT_NO_FILESYSTEMWATCHER diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.cpp b/src/corelib/io/qfilesystemwatcher_fsevents.cpp deleted file mode 100644 index 95da897974..0000000000 --- a/src/corelib/io/qfilesystemwatcher_fsevents.cpp +++ /dev/null @@ -1,492 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#define _DARWIN_USE_64_BIT_INODE -#include <qplatformdefs.h> - -#include "qfilesystemwatcher.h" -#include "qfilesystemwatcher_fsevents_p.h" - -#ifndef QT_NO_FILESYSTEMWATCHER - -#include <qdebug.h> -#include <qfile.h> -#include <qdatetime.h> -#include <qfileinfo.h> -#include <qvarlengtharray.h> - -#include <mach/mach.h> -#include <sys/types.h> -#include <CoreFoundation/CFRunLoop.h> -#include <CoreFoundation/CFUUID.h> -#include <CoreServices/CoreServices.h> -#include <AvailabilityMacros.h> -#include <private/qcore_mac_p.h> - -QT_BEGIN_NAMESPACE - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 -// Static operator overloading so for the sake of some convieniece. -// They only live in this compilation unit to avoid polluting Qt in general. -static bool operator==(const struct ::timespec &left, const struct ::timespec &right) -{ - return left.tv_sec == right.tv_sec - && left.tv_nsec == right.tv_nsec; -} - -static bool operator==(const struct ::stat &left, const struct ::stat &right) -{ - return left.st_dev == right.st_dev - && left.st_mode == right.st_mode - && left.st_size == right.st_size - && left.st_ino == right.st_ino - && left.st_uid == right.st_uid - && left.st_gid == right.st_gid - && left.st_mtimespec == right.st_mtimespec - && left.st_ctimespec == right.st_ctimespec - && left.st_flags == right.st_flags; -} - -static bool operator!=(const struct ::stat &left, const struct ::stat &right) -{ - return !(operator==(left, right)); -} - - -static void addPathToHash(PathHash &pathHash, const QString &key, const QFileInfo &fileInfo, - const QString &path) -{ - PathInfoList &list = pathHash[key]; - list.push_back(PathInfo(path, - fileInfo.canonicalFilePath().normalized(QString::NormalizationForm_D).toUtf8())); - pathHash.insert(key, list); -} - -static void removePathFromHash(PathHash &pathHash, const QString &key, const QString &path) -{ - PathInfoList &list = pathHash[key]; - // We make the assumption that the list contains unique paths - PathInfoList::iterator End = list.end(); - PathInfoList::iterator it = list.begin(); - while (it != End) { - if (it->originalPath == path) { - list.erase(it); - break; - } - ++it; - } - if (list.isEmpty()) - pathHash.remove(key); -} - -static void stopFSStream(FSEventStreamRef stream) -{ - if (stream) { - FSEventStreamStop(stream); - FSEventStreamInvalidate(stream); - } -} - -static QString createFSStreamPath(const QString &absolutePath) -{ - // The path returned has a trailing slash, so ensure that here. - QString string = absolutePath; - string.reserve(string.size() + 1); - string.append(QLatin1Char('/')); - return string; -} - -static void cleanupFSStream(FSEventStreamRef stream) -{ - if (stream) - FSEventStreamRelease(stream); -} - -const FSEventStreamCreateFlags QtFSEventFlags = (kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagNoDefer /* | kFSEventStreamCreateFlagWatchRoot*/); - -const CFTimeInterval Latency = 0.033; // This will do updates 30 times a second which is probably more than you need. -#endif - -QFSEventsFileSystemWatcherEngine::QFSEventsFileSystemWatcherEngine() - : fsStream(0), pathsToWatch(0), threadsRunLoop(0) -{ -} - -QFSEventsFileSystemWatcherEngine::~QFSEventsFileSystemWatcherEngine() -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - // I assume that at this point, QFileSystemWatcher has already called stop - // on me, so I don't need to invalidate or stop my stream, simply - // release it. - cleanupFSStream(fsStream); - if (pathsToWatch) - CFRelease(pathsToWatch); -#endif -} - -QFSEventsFileSystemWatcherEngine *QFSEventsFileSystemWatcherEngine::create() -{ - return new QFSEventsFileSystemWatcherEngine(); -} - -QStringList QFSEventsFileSystemWatcherEngine::addPaths(const QStringList &paths, - QStringList *files, - QStringList *directories) -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - stop(); - wait(); - QMutexLocker locker(&mutex); - QStringList failedToAdd; - // if we have a running FSStreamEvent, we have to kill it, we'll re-add the stream soon. - FSEventStreamEventId idToCheck; - if (fsStream) { - idToCheck = FSEventStreamGetLatestEventId(fsStream); - cleanupFSStream(fsStream); - } else { - idToCheck = kFSEventStreamEventIdSinceNow; - } - - // Brain-dead approach, but works. FSEvents actually can already read sub-trees, but since it's - // work to figure out if we are doing a double register, we just register it twice as FSEvents - // seems smart enough to only deliver one event. We also duplicate directory entries in here - // (e.g., if you watch five files in the same directory, you get that directory included in the - // array 5 times). This stupidity also makes remove work correctly though. I'll freely admit - // that we could make this a bit smarter. If you do, check the auto-tests, they should catch at - // least a couple of the issues. - QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - for (int i = 0; i < paths.size(); ++i) { - const QString &path = paths.at(i); - - QFileInfo fileInfo(path); - if (!fileInfo.exists()) { - failedToAdd.append(path); - continue; - } - - if (fileInfo.isDir()) { - if (directories->contains(path)) { - failedToAdd.append(path); - continue; - } else { - directories->append(path); - // Full file path for dirs. - QCFString cfpath(createFSStreamPath(fileInfo.canonicalFilePath())); - addPathToHash(dirPathInfoHash, cfpath, fileInfo, path); - CFArrayAppendValue(tmpArray, cfpath); - } - } else { - if (files->contains(path)) { - failedToAdd.append(path); - continue; - } else { - // Just the absolute path (minus it's filename) for files. - QCFString cfpath(createFSStreamPath(fileInfo.canonicalPath())); - files->append(path); - addPathToHash(filePathInfoHash, cfpath, fileInfo, path); - CFArrayAppendValue(tmpArray, cfpath); - } - } - } - - if (!pathsToWatch && failedToAdd.size() == paths.size()) { - return failedToAdd; - } - - if (CFArrayGetCount(tmpArray) > 0) { - if (pathsToWatch) { - CFArrayAppendArray(tmpArray, pathsToWatch, CFRangeMake(0, CFArrayGetCount(pathsToWatch))); - CFRelease(pathsToWatch); - } - pathsToWatch = CFArrayCreateCopy(kCFAllocatorDefault, tmpArray); - } - - FSEventStreamContext context = { 0, this, 0, 0, 0 }; - fsStream = FSEventStreamCreate(kCFAllocatorDefault, - QFSEventsFileSystemWatcherEngine::fseventsCallback, - &context, pathsToWatch, - idToCheck, Latency, QtFSEventFlags); - warmUpFSEvents(); - - return failedToAdd; -#else - Q_UNUSED(paths); - Q_UNUSED(files); - Q_UNUSED(directories); - return QStringList(); -#endif -} - -void QFSEventsFileSystemWatcherEngine::warmUpFSEvents() -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - // This function assumes that the mutex has already been grabbed before calling it. - // It exits with the mutex still locked (Q_ASSERT(mutex.isLocked()) ;-). - start(); - waitCondition.wait(&mutex); -#endif -} - -QStringList QFSEventsFileSystemWatcherEngine::removePaths(const QStringList &paths, - QStringList *files, - QStringList *directories) -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - stop(); - wait(); - QMutexLocker locker(&mutex); - // short circuit for smarties that call remove before add and we have nothing. - if (pathsToWatch == 0) - return paths; - QStringList failedToRemove; - // if we have a running FSStreamEvent, we have to stop it, we'll re-add the stream soon. - FSEventStreamEventId idToCheck; - if (fsStream) { - idToCheck = FSEventStreamGetLatestEventId(fsStream); - cleanupFSStream(fsStream); - fsStream = 0; - } else { - idToCheck = kFSEventStreamEventIdSinceNow; - } - - CFIndex itemCount = CFArrayGetCount(pathsToWatch); - QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutableCopy(kCFAllocatorDefault, itemCount, - pathsToWatch); - CFRelease(pathsToWatch); - pathsToWatch = 0; - for (int i = 0; i < paths.size(); ++i) { - // Get the itemCount at the beginning to avoid any overruns during the iteration. - itemCount = CFArrayGetCount(tmpArray); - const QString &path = paths.at(i); - QFileInfo fi(path); - QCFString cfpath(createFSStreamPath(fi.canonicalPath())); - - CFIndex index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfpath); - if (index != -1) { - CFArrayRemoveValueAtIndex(tmpArray, index); - files->removeAll(path); - removePathFromHash(filePathInfoHash, cfpath, path); - } else { - // Could be a directory we are watching instead. - QCFString cfdirpath(createFSStreamPath(fi.canonicalFilePath())); - index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfdirpath); - if (index != -1) { - CFArrayRemoveValueAtIndex(tmpArray, index); - directories->removeAll(path); - removePathFromHash(dirPathInfoHash, cfpath, path); - } else { - failedToRemove.append(path); - } - } - } - itemCount = CFArrayGetCount(tmpArray); - if (itemCount != 0) { - pathsToWatch = CFArrayCreateCopy(kCFAllocatorDefault, tmpArray); - - FSEventStreamContext context = { 0, this, 0, 0, 0 }; - fsStream = FSEventStreamCreate(kCFAllocatorDefault, - QFSEventsFileSystemWatcherEngine::fseventsCallback, - &context, pathsToWatch, idToCheck, Latency, QtFSEventFlags); - warmUpFSEvents(); - } - return failedToRemove; -#else - Q_UNUSED(paths); - Q_UNUSED(files); - Q_UNUSED(directories); - return QStringList(); -#endif -} - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 -void QFSEventsFileSystemWatcherEngine::updateList(PathInfoList &list, bool directory, bool emitSignals) -{ - PathInfoList::iterator End = list.end(); - PathInfoList::iterator it = list.begin(); - while (it != End) { - struct ::stat newInfo; - if (::stat(it->absolutePath, &newInfo) == 0) { - if (emitSignals) { - if (newInfo != it->savedInfo) { - it->savedInfo = newInfo; - if (directory) - emit directoryChanged(it->originalPath, false); - else - emit fileChanged(it->originalPath, false); - } - } else { - it->savedInfo = newInfo; - } - } else { - if (errno == ENOENT) { - if (emitSignals) { - if (directory) - emit directoryChanged(it->originalPath, true); - else - emit fileChanged(it->originalPath, true); - } - it = list.erase(it); - continue; - } else { - qWarning("%s:%d:QFSEventsFileSystemWatcherEngine: stat error on %s:%s", - __FILE__, __LINE__, qPrintable(it->originalPath), strerror(errno)); - - } - } - ++it; - } -} - -void QFSEventsFileSystemWatcherEngine::updateHash(PathHash &pathHash) -{ - PathHash::iterator HashEnd = pathHash.end(); - PathHash::iterator it = pathHash.begin(); - const bool IsDirectory = (&pathHash == &dirPathInfoHash); - while (it != HashEnd) { - updateList(it.value(), IsDirectory, false); - if (it.value().isEmpty()) - it = pathHash.erase(it); - else - ++it; - } -} -#endif - -void QFSEventsFileSystemWatcherEngine::fseventsCallback(ConstFSEventStreamRef , - void *clientCallBackInfo, size_t numEvents, - void *eventPaths, - const FSEventStreamEventFlags eventFlags[], - const FSEventStreamEventId []) -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - QFSEventsFileSystemWatcherEngine *watcher = static_cast<QFSEventsFileSystemWatcherEngine *>(clientCallBackInfo); - QMutexLocker locker(&watcher->mutex); - CFArrayRef paths = static_cast<CFArrayRef>(eventPaths); - for (size_t i = 0; i < numEvents; ++i) { - const QString path = QCFString::toQString( - static_cast<CFStringRef>(CFArrayGetValueAtIndex(paths, i))); - const FSEventStreamEventFlags pathFlags = eventFlags[i]; - // There are several flags that may be passed, but we really don't care about them ATM. - // Here they are and why we don't care. - // kFSEventStreamEventFlagHistoryDone--(very unlikely to be gotten, but even then, not much changes). - // kFSEventStreamEventFlagMustScanSubDirs--Likely means the data is very much out of date, we - // aren't coalescing our directories, so again not so much of an issue - // kFSEventStreamEventFlagRootChanged | kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount-- - // These three flags indicate something has changed, but the stat will likely show this, so - // there's not really much to worry about. - // (btw, FSEvents is not the correct way of checking for mounts/unmounts, - // there are real CarbonCore events for that.) - Q_UNUSED(pathFlags); - if (watcher->filePathInfoHash.contains(path)) - watcher->updateList(watcher->filePathInfoHash[path], false, true); - - if (watcher->dirPathInfoHash.contains(path)) - watcher->updateList(watcher->dirPathInfoHash[path], true, true); - } -#else - Q_UNUSED(clientCallBackInfo); - Q_UNUSED(numEvents); - Q_UNUSED(eventPaths); - Q_UNUSED(eventFlags); -#endif -} - -void QFSEventsFileSystemWatcherEngine::stop() -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - QMutexLocker locker(&mutex); - stopFSStream(fsStream); - if (threadsRunLoop) { - CFRunLoopStop(threadsRunLoop); - waitForStop.wait(&mutex); - } -#endif -} - -void QFSEventsFileSystemWatcherEngine::updateFiles() -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - QMutexLocker locker(&mutex); - updateHash(filePathInfoHash); - updateHash(dirPathInfoHash); - if (filePathInfoHash.isEmpty() && dirPathInfoHash.isEmpty()) { - // Everything disappeared before we got to start, don't bother. -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - // Code duplicated from stop(), with the exception that we - // don't wait on waitForStop here. Doing this will lead to - // a deadlock since this function is called from the worker - // thread. (waitForStop.wakeAll() is only called from the - // end of run()). - stopFSStream(fsStream); - if (threadsRunLoop) - CFRunLoopStop(threadsRunLoop); -#endif - cleanupFSStream(fsStream); - } - waitCondition.wakeAll(); -#endif -} - -void QFSEventsFileSystemWatcherEngine::run() -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - threadsRunLoop = CFRunLoopGetCurrent(); - FSEventStreamScheduleWithRunLoop(fsStream, threadsRunLoop, kCFRunLoopDefaultMode); - bool startedOK = FSEventStreamStart(fsStream); - // It's recommended by Apple that you only update the files after you've started - // the stream, because otherwise you might miss an update in between starting it. - updateFiles(); -#ifdef QT_NO_DEBUG - Q_UNUSED(startedOK); -#else - Q_ASSERT(startedOK); -#endif - // If for some reason we called stop up above (and invalidated our stream), this call will return - // immediately. - CFRunLoopRun(); - threadsRunLoop = 0; - QMutexLocker locker(&mutex); - waitForStop.wakeAll(); -#endif -} - -QT_END_NAMESPACE -#endif //QT_NO_FILESYSTEMWATCHER diff --git a/src/corelib/io/qfilesystemwatcher_fsevents_p.h b/src/corelib/io/qfilesystemwatcher_fsevents_p.h deleted file mode 100644 index 3830002c0a..0000000000 --- a/src/corelib/io/qfilesystemwatcher_fsevents_p.h +++ /dev/null @@ -1,132 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef FILEWATCHER_FSEVENTS_P_H -#define FILEWATCHER_FSEVENTS_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the QLibrary class. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include "qfilesystemwatcher_p.h" - -#ifndef QT_NO_FILESYSTEMWATCHER - -#include <QtCore/qmutex.h> -#include <QtCore/qwaitcondition.h> -#include <QtCore/qthread.h> -#include <QtCore/qhash.h> -#include <QtCore/qlinkedlist.h> -#include <private/qcore_mac_p.h> -#include <sys/stat.h> - -typedef struct __FSEventStream *FSEventStreamRef; -typedef const struct __FSEventStream *ConstFSEventStreamRef; -typedef const struct __CFArray *CFArrayRef; -typedef UInt32 FSEventStreamEventFlags; -typedef uint64_t FSEventStreamEventId; - -QT_BEGIN_NAMESPACE - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 -// Yes, I use a stat element here. QFileInfo requires too much knowledge about implementation -// details to be used as a long-standing record. Since I'm going to have to store this information, I can -// do the stat myself too. -struct PathInfo { - PathInfo(const QString &path, const QByteArray &absPath) - : originalPath(path), absolutePath(absPath) {} - QString originalPath; // The path we need to emit - QByteArray absolutePath; // The path we need to stat. - struct ::stat savedInfo; // All the info for the path so we can compare it. -}; -typedef QLinkedList<PathInfo> PathInfoList; -typedef QHash<QString, PathInfoList> PathHash; -#endif - -class QFSEventsFileSystemWatcherEngine : public QFileSystemWatcherEngine -{ - Q_OBJECT -public: - ~QFSEventsFileSystemWatcherEngine(); - - static QFSEventsFileSystemWatcherEngine *create(); - - QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); - QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); - - void stop(); - -private: - QFSEventsFileSystemWatcherEngine(); - void warmUpFSEvents(); - void updateFiles(); - - static void fseventsCallback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, - void *eventPaths, const FSEventStreamEventFlags eventFlags[], - const FSEventStreamEventId eventIds[]); - void run(); - FSEventStreamRef fsStream; - CFArrayRef pathsToWatch; - CFRunLoopRef threadsRunLoop; - QMutex mutex; - QWaitCondition waitCondition; - QWaitCondition waitForStop; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - PathHash filePathInfoHash; - PathHash dirPathInfoHash; - void updateHash(PathHash &pathHash); - void updateList(PathInfoList &list, bool directory, bool emitSignals); -#endif -}; - -#endif //QT_NO_FILESYSTEMWATCHER - -#endif - -QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp index ef302243da..ff732bc70e 100644 --- a/src/corelib/io/qfilesystemwatcher_inotify.cpp +++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -210,7 +210,7 @@ QT_END_NAMESPACE QT_BEGIN_NAMESPACE -QInotifyFileSystemWatcherEngine *QInotifyFileSystemWatcherEngine::create() +QInotifyFileSystemWatcherEngine *QInotifyFileSystemWatcherEngine::create(QObject *parent) { register int fd = -1; #ifdef IN_CLOEXEC @@ -220,40 +220,32 @@ QInotifyFileSystemWatcherEngine *QInotifyFileSystemWatcherEngine::create() fd = inotify_init(); if (fd == -1) return 0; - ::fcntl(fd, F_SETFD, FD_CLOEXEC); } - return new QInotifyFileSystemWatcherEngine(fd); + return new QInotifyFileSystemWatcherEngine(fd, parent); } -QInotifyFileSystemWatcherEngine::QInotifyFileSystemWatcherEngine(int fd) - : inotifyFd(fd) +QInotifyFileSystemWatcherEngine::QInotifyFileSystemWatcherEngine(int fd, QObject *parent) + : QFileSystemWatcherEngine(parent), + inotifyFd(fd), + notifier(fd, QSocketNotifier::Read, this) { fcntl(inotifyFd, F_SETFD, FD_CLOEXEC); - - moveToThread(this); + connect(¬ifier, SIGNAL(activated(int)), SLOT(readFromInotify())); } QInotifyFileSystemWatcherEngine::~QInotifyFileSystemWatcherEngine() { + notifier.setEnabled(false); foreach (int id, pathToID) inotify_rm_watch(inotifyFd, id < 0 ? -id : id); ::close(inotifyFd); } -void QInotifyFileSystemWatcherEngine::run() -{ - QSocketNotifier sn(inotifyFd, QSocketNotifier::Read, this); - connect(&sn, SIGNAL(activated(int)), SLOT(readFromInotify())); - (void) exec(); -} - QStringList QInotifyFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *files, QStringList *directories) { - QMutexLocker locker(&mutex); - QStringList p = paths; QMutableListIterator<QString> it(p); while (it.hasNext()) { @@ -303,8 +295,6 @@ QStringList QInotifyFileSystemWatcherEngine::addPaths(const QStringList &paths, idToPath.insert(id, path); } - start(); - return p; } @@ -312,8 +302,6 @@ QStringList QInotifyFileSystemWatcherEngine::removePaths(const QStringList &path QStringList *files, QStringList *directories) { - QMutexLocker locker(&mutex); - QStringList p = paths; QMutableListIterator<QString> it(p); while (it.hasNext()) { @@ -338,15 +326,8 @@ QStringList QInotifyFileSystemWatcherEngine::removePaths(const QStringList &path return p; } -void QInotifyFileSystemWatcherEngine::stop() -{ - quit(); -} - void QInotifyFileSystemWatcherEngine::readFromInotify() { - QMutexLocker locker(&mutex); - // qDebug() << "QInotifyFileSystemWatcherEngine::readFromInotify"; int buffSize = 0; diff --git a/src/corelib/io/qfilesystemwatcher_inotify_p.h b/src/corelib/io/qfilesystemwatcher_inotify_p.h index 0abd205237..8b3ce62c46 100644 --- a/src/corelib/io/qfilesystemwatcher_inotify_p.h +++ b/src/corelib/io/qfilesystemwatcher_inotify_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -57,8 +57,9 @@ #ifndef QT_NO_FILESYSTEMWATCHER -#include <qhash.h> -#include <qmutex.h> +#include <QtCore/qhash.h> +#include <QtCore/qmutex.h> +#include <QtCore/qsocketnotifier.h> QT_BEGIN_NAMESPACE @@ -69,24 +70,20 @@ class QInotifyFileSystemWatcherEngine : public QFileSystemWatcherEngine public: ~QInotifyFileSystemWatcherEngine(); - static QInotifyFileSystemWatcherEngine *create(); - - void run(); + static QInotifyFileSystemWatcherEngine *create(QObject *parent); QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); - void stop(); - private Q_SLOTS: void readFromInotify(); private: - QInotifyFileSystemWatcherEngine(int fd); + QInotifyFileSystemWatcherEngine(int fd, QObject *parent); int inotifyFd; - QMutex mutex; QHash<QString, int> pathToID; QHash<int, QString> idToPath; + QSocketNotifier notifier; }; diff --git a/src/corelib/io/qfilesystemwatcher_kqueue.cpp b/src/corelib/io/qfilesystemwatcher_kqueue.cpp index 387a7f7c4b..fd7bfa2b27 100644 --- a/src/corelib/io/qfilesystemwatcher_kqueue.cpp +++ b/src/corelib/io/qfilesystemwatcher_kqueue.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -67,49 +67,28 @@ QT_BEGIN_NAMESPACE # define DEBUG if(false)qDebug #endif -QKqueueFileSystemWatcherEngine *QKqueueFileSystemWatcherEngine::create() +QKqueueFileSystemWatcherEngine *QKqueueFileSystemWatcherEngine::create(QObject *parent) { int kqfd = kqueue(); if (kqfd == -1) return 0; - return new QKqueueFileSystemWatcherEngine(kqfd); + return new QKqueueFileSystemWatcherEngine(kqfd, parent); } -QKqueueFileSystemWatcherEngine::QKqueueFileSystemWatcherEngine(int kqfd) - : kqfd(kqfd) +QKqueueFileSystemWatcherEngine::QKqueueFileSystemWatcherEngine(int kqfd, QObject *parent) + : QFileSystemWatcherEngine(parent), + kqfd(kqfd), + notifier(kqfd, QSocketNotifier::Read, this) { - fcntl(kqfd, F_SETFD, FD_CLOEXEC); + connect(¬ifier, SIGNAL(activated(int)), SLOT(readFromKqueue())); - if (pipe(kqpipe) == -1) { - perror("QKqueueFileSystemWatcherEngine: cannot create pipe"); - kqpipe[0] = kqpipe[1] = -1; - return; - } - fcntl(kqpipe[0], F_SETFD, FD_CLOEXEC); - fcntl(kqpipe[1], F_SETFD, FD_CLOEXEC); - - struct kevent kev; - EV_SET(&kev, - kqpipe[0], - EVFILT_READ, - EV_ADD | EV_ENABLE, - 0, - 0, - 0); - if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) { - perror("QKqueueFileSystemWatcherEngine: cannot watch pipe, kevent returned"); - return; - } + fcntl(kqfd, F_SETFD, FD_CLOEXEC); } QKqueueFileSystemWatcherEngine::~QKqueueFileSystemWatcherEngine() { - stop(); - wait(); - + notifier.setEnabled(false); close(kqfd); - close(kqpipe[0]); - close(kqpipe[1]); foreach (int id, pathToID) ::close(id < 0 ? -id : id); @@ -120,82 +99,73 @@ QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *directories) { QStringList p = paths; - { - QMutexLocker locker(&mutex); - - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - int fd; + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + int fd; #if defined(O_EVTONLY) - fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY); + fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY); #else - fd = qt_safe_open(QFile::encodeName(path), O_RDONLY); + fd = qt_safe_open(QFile::encodeName(path), O_RDONLY); #endif - if (fd == -1) { - perror("QKqueueFileSystemWatcherEngine::addPaths: open"); - continue; - } - if (fd >= (int)FD_SETSIZE / 2 && fd < (int)FD_SETSIZE) { - int fddup = fcntl(fd, F_DUPFD, FD_SETSIZE); - if (fddup != -1) { - ::close(fd); - fd = fddup; - } + if (fd == -1) { + perror("QKqueueFileSystemWatcherEngine::addPaths: open"); + continue; + } + if (fd >= (int)FD_SETSIZE / 2 && fd < (int)FD_SETSIZE) { + int fddup = fcntl(fd, F_DUPFD, FD_SETSIZE); + if (fddup != -1) { + ::close(fd); + fd = fddup; } - fcntl(fd, F_SETFD, FD_CLOEXEC); + } + fcntl(fd, F_SETFD, FD_CLOEXEC); - QT_STATBUF st; - if (QT_FSTAT(fd, &st) == -1) { - perror("QKqueueFileSystemWatcherEngine::addPaths: fstat"); + QT_STATBUF st; + if (QT_FSTAT(fd, &st) == -1) { + perror("QKqueueFileSystemWatcherEngine::addPaths: fstat"); + ::close(fd); + continue; + } + int id = (S_ISDIR(st.st_mode)) ? -fd : fd; + if (id < 0) { + if (directories->contains(path)) { ::close(fd); continue; } - int id = (S_ISDIR(st.st_mode)) ? -fd : fd; - if (id < 0) { - if (directories->contains(path)) { - ::close(fd); - continue; - } - } else { - if (files->contains(path)) { - ::close(fd); - continue; - } - } - - struct kevent kev; - EV_SET(&kev, - fd, - EVFILT_VNODE, - EV_ADD | EV_ENABLE | EV_CLEAR, - NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, - 0, - 0); - if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) { - perror("QKqueueFileSystemWatcherEngine::addPaths: kevent"); + } else { + if (files->contains(path)) { ::close(fd); continue; } + } - it.remove(); - if (id < 0) { - DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path; - directories->append(path); - } else { - DEBUG() << "QKqueueFileSystemWatcherEngine: added file path" << path; - files->append(path); - } + struct kevent kev; + EV_SET(&kev, + fd, + EVFILT_VNODE, + EV_ADD | EV_ENABLE | EV_CLEAR, + NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, + 0, + 0); + if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) { + perror("QKqueueFileSystemWatcherEngine::addPaths: kevent"); + ::close(fd); + continue; + } - pathToID.insert(path, id); - idToPath.insert(id, path); + it.remove(); + if (id < 0) { + DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path; + directories->append(path); + } else { + DEBUG() << "QKqueueFileSystemWatcherEngine: added file path" << path; + files->append(path); } - } - if (!isRunning()) - start(); - else - write(kqpipe[1], "@", 1); + pathToID.insert(path, id); + idToPath.insert(id, path); + } return p; } @@ -206,126 +176,86 @@ QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths { bool isEmpty; QStringList p = paths; - { - QMutexLocker locker(&mutex); - if (pathToID.isEmpty()) - return p; - - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - int id = pathToID.take(path); - QString x = idToPath.take(id); - if (x.isEmpty() || x != path) - continue; + if (pathToID.isEmpty()) + return p; - ::close(id < 0 ? -id : id); + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + int id = pathToID.take(path); + QString x = idToPath.take(id); + if (x.isEmpty() || x != path) + continue; - it.remove(); - if (id < 0) - directories->removeAll(path); - else - files->removeAll(path); - } - isEmpty = pathToID.isEmpty(); - } + ::close(id < 0 ? -id : id); - if (isEmpty) { - stop(); - wait(); - } else { - write(kqpipe[1], "@", 1); + it.remove(); + if (id < 0) + directories->removeAll(path); + else + files->removeAll(path); } + isEmpty = pathToID.isEmpty(); return p; } -void QKqueueFileSystemWatcherEngine::stop() -{ - write(kqpipe[1], "q", 1); -} - -void QKqueueFileSystemWatcherEngine::run() +void QKqueueFileSystemWatcherEngine::readFromKqueue() { forever { + DEBUG() << "QKqueueFileSystemWatcherEngine: polling for changes"; int r; struct kevent kev; - DEBUG() << "QKqueueFileSystemWatcherEngine: waiting for kevents..."; - EINTR_LOOP(r, kevent(kqfd, 0, 0, &kev, 1, 0)); + struct timespec ts = { 0, 0 }; // 0 ts, because we want to poll + EINTR_LOOP(r, kevent(kqfd, 0, 0, &kev, 1, &ts)); if (r < 0) { perror("QKqueueFileSystemWatcherEngine: error during kevent wait"); return; + } else if (r == 0) { + // polling returned no events, so stop + break; } else { int fd = kev.ident; DEBUG() << "QKqueueFileSystemWatcherEngine: processing kevent" << kev.ident << kev.filter; - if (fd == kqpipe[0]) { - // read all pending data from the pipe - QByteArray ba; - ba.resize(kev.data); - if (read(kqpipe[0], ba.data(), ba.size()) != ba.size()) { - perror("QKqueueFileSystemWatcherEngine: error reading from pipe"); - return; - } - // read the command from the buffer (but break and return on 'q') - char cmd = 0; - for (int i = 0; i < ba.size(); ++i) { - cmd = ba.constData()[i]; - if (cmd == 'q') - break; - } - // handle the command - switch (cmd) { - case 'q': - DEBUG() << "QKqueueFileSystemWatcherEngine: thread received 'q', exiting..."; - return; - case '@': - DEBUG() << "QKqueueFileSystemWatcherEngine: thread received '@', continuing..."; - break; - default: - DEBUG() << "QKqueueFileSystemWatcherEngine: thread received unknow message" << cmd; - break; - } - } else { - QMutexLocker locker(&mutex); - int id = fd; - QString path = idToPath.value(id); + int id = fd; + QString path = idToPath.value(id); + if (path.isEmpty()) { + // perhaps a directory? + id = -id; + path = idToPath.value(id); if (path.isEmpty()) { - // perhaps a directory? - id = -id; - path = idToPath.value(id); - if (path.isEmpty()) { - DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent for a file we're not watching"; - continue; - } - } - if (kev.filter != EVFILT_VNODE) { - DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent with the wrong filter"; + DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent for a file we're not watching"; continue; } + } + if (kev.filter != EVFILT_VNODE) { + DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent with the wrong filter"; + continue; + } - if ((kev.fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) != 0) { - DEBUG() << path << "removed, removing watch also"; + if ((kev.fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) != 0) { + DEBUG() << path << "removed, removing watch also"; - pathToID.remove(path); - idToPath.remove(id); - ::close(fd); + pathToID.remove(path); + idToPath.remove(id); + ::close(fd); - if (id < 0) - emit directoryChanged(path, true); - else - emit fileChanged(path, true); - } else { - DEBUG() << path << "changed"; + if (id < 0) + emit directoryChanged(path, true); + else + emit fileChanged(path, true); + } else { + DEBUG() << path << "changed"; - if (id < 0) - emit directoryChanged(path, false); - else - emit fileChanged(path, false); - } + if (id < 0) + emit directoryChanged(path, false); + else + emit fileChanged(path, false); } } + } } diff --git a/src/corelib/io/qfilesystemwatcher_kqueue_p.h b/src/corelib/io/qfilesystemwatcher_kqueue_p.h index fd9d820e7d..9bd9378c0c 100644 --- a/src/corelib/io/qfilesystemwatcher_kqueue_p.h +++ b/src/corelib/io/qfilesystemwatcher_kqueue_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -59,6 +59,7 @@ #include <QtCore/qmutex.h> #include <QtCore/qthread.h> #include <QtCore/qvector.h> +#include <QtCore/qsocketnotifier.h> #ifndef QT_NO_FILESYSTEMWATCHER struct kevent; @@ -71,24 +72,22 @@ class QKqueueFileSystemWatcherEngine : public QFileSystemWatcherEngine public: ~QKqueueFileSystemWatcherEngine(); - static QKqueueFileSystemWatcherEngine *create(); + static QKqueueFileSystemWatcherEngine *create(QObject *parent); QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); - void stop(); +private Q_SLOTS: + void readFromKqueue(); private: - QKqueueFileSystemWatcherEngine(int kqfd); - - void run(); + QKqueueFileSystemWatcherEngine(int kqfd, QObject *parent); int kqfd; - int kqpipe[2]; - QMutex mutex; QHash<QString, int> pathToID; QHash<int, QString> idToPath; + QSocketNotifier notifier; }; QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h index e136273b36..9f403b308f 100644 --- a/src/corelib/io/qfilesystemwatcher_p.h +++ b/src/corelib/io/qfilesystemwatcher_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -60,19 +60,17 @@ #include <private/qobject_p.h> #include <QtCore/qstringlist.h> -#include <QtCore/qthread.h> QT_BEGIN_NAMESPACE -class QFileSystemWatcherEngine : public QThread +class QFileSystemWatcherEngine : public QObject { Q_OBJECT protected: - inline QFileSystemWatcherEngine(bool move = true) + inline QFileSystemWatcherEngine(QObject *parent) + : QObject(parent) { - if (move) - moveToThread(this); } public: @@ -88,8 +86,6 @@ public: QStringList *files, QStringList *directories) = 0; - virtual void stop() = 0; - Q_SIGNALS: void fileChanged(const QString &path, bool removed); void directoryChanged(const QString &path, bool removed); @@ -99,15 +95,14 @@ class QFileSystemWatcherPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QFileSystemWatcher) - static QFileSystemWatcherEngine *createNativeEngine(); + static QFileSystemWatcherEngine *createNativeEngine(QObject *parent); public: QFileSystemWatcherPrivate(); void init(); void initPollerEngine(); - void initForcedEngine(const QString &); - QFileSystemWatcherEngine *native, *poller, *forced; + QFileSystemWatcherEngine *native, *poller; QStringList files, directories; // private slots diff --git a/src/corelib/io/qfilesystemwatcher_polling.cpp b/src/corelib/io/qfilesystemwatcher_polling.cpp new file mode 100644 index 0000000000..23dca140d6 --- /dev/null +++ b/src/corelib/io/qfilesystemwatcher_polling.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfilesystemwatcher_polling_p.h" +#include <QtCore/qtimer.h> + +QT_BEGIN_NAMESPACE + +QPollingFileSystemWatcherEngine::QPollingFileSystemWatcherEngine(QObject *parent) + : QFileSystemWatcherEngine(parent), + timer(this) +{ + connect(&timer, SIGNAL(timeout()), SLOT(timeout())); +} + +QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths, + QStringList *files, + QStringList *directories) +{ + QStringList p = paths; + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + QFileInfo fi(path); + if (!fi.exists()) + continue; + if (fi.isDir()) { + if (!directories->contains(path)) + directories->append(path); + if (!path.endsWith(QLatin1Char('/'))) + fi = QFileInfo(path + QLatin1Char('/')); + this->directories.insert(path, fi); + } else { + if (!files->contains(path)) + files->append(path); + this->files.insert(path, fi); + } + it.remove(); + } + + if ((!this->files.isEmpty() || + !this->directories.isEmpty()) && + !timer.isActive()) { + timer.start(PollingInterval); + } + + return p; +} + +QStringList QPollingFileSystemWatcherEngine::removePaths(const QStringList &paths, + QStringList *files, + QStringList *directories) +{ + QStringList p = paths; + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + if (this->directories.remove(path)) { + directories->removeAll(path); + it.remove(); + } else if (this->files.remove(path)) { + files->removeAll(path); + it.remove(); + } + } + + if (this->files.isEmpty() && + this->directories.isEmpty()) { + timer.stop(); + } + + return p; +} + +void QPollingFileSystemWatcherEngine::timeout() +{ + QMutableHashIterator<QString, FileInfo> fit(files); + while (fit.hasNext()) { + QHash<QString, FileInfo>::iterator x = fit.next(); + QString path = x.key(); + QFileInfo fi(path); + if (!fi.exists()) { + fit.remove(); + emit fileChanged(path, true); + } else if (x.value() != fi) { + x.value() = fi; + emit fileChanged(path, false); + } + } + QMutableHashIterator<QString, FileInfo> dit(directories); + while (dit.hasNext()) { + QHash<QString, FileInfo>::iterator x = dit.next(); + QString path = x.key(); + QFileInfo fi(path); + if (!path.endsWith(QLatin1Char('/'))) + fi = QFileInfo(path + QLatin1Char('/')); + if (!fi.exists()) { + dit.remove(); + emit directoryChanged(path, true); + } else if (x.value() != fi) { + fi.refresh(); + if (!fi.exists()) { + dit.remove(); + emit directoryChanged(path, true); + } else { + x.value() = fi; + emit directoryChanged(path, false); + } + } + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemwatcher_dnotify_p.h b/src/corelib/io/qfilesystemwatcher_polling_p.h index f759e87d89..3b3272a890 100644 --- a/src/corelib/io/qfilesystemwatcher_dnotify_p.h +++ b/src/corelib/io/qfilesystemwatcher_polling_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QFILESYSTEMWATCHER_DNOTIFY_P_H -#define QFILESYSTEMWATCHER_DNOTIFY_P_H +#ifndef QFILESYSTEMWATCHER_POLLING_P_H +#define QFILESYSTEMWATCHER_POLLING_P_H // // W A R N I N G @@ -53,79 +53,74 @@ // We mean it. // -#include "qfilesystemwatcher_p.h" - -#ifndef QT_NO_FILESYSTEMWATCHER +#include <QtCore/qfileinfo.h> +#include <QtCore/qmutex.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qdir.h> +#include <QtCore/qtimer.h> -#include <qmutex.h> -#include <qhash.h> -#include <qdatetime.h> -#include <qfile.h> +#include "qfilesystemwatcher_p.h" QT_BEGIN_NAMESPACE -class QDnotifyFileSystemWatcherEngine : public QFileSystemWatcherEngine +enum { PollingInterval = 1000 }; + +class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine { Q_OBJECT -public: - virtual ~QDnotifyFileSystemWatcherEngine(); + class FileInfo + { + uint ownerId; + uint groupId; + QFile::Permissions permissions; + QDateTime lastModified; + QStringList entries; + + public: + FileInfo(const QFileInfo &fileInfo) + : ownerId(fileInfo.ownerId()), + groupId(fileInfo.groupId()), + permissions(fileInfo.permissions()), + lastModified(fileInfo.lastModified()) + { + if (fileInfo.isDir()) { + entries = fileInfo.absoluteDir().entryList(QDir::AllEntries); + } + } + FileInfo &operator=(const QFileInfo &fileInfo) + { + *this = FileInfo(fileInfo); + return *this; + } + + bool operator!=(const QFileInfo &fileInfo) const + { + if (fileInfo.isDir() && entries != fileInfo.absoluteDir().entryList(QDir::AllEntries)) + return true; + return (ownerId != fileInfo.ownerId() + || groupId != fileInfo.groupId() + || permissions != fileInfo.permissions() + || lastModified != fileInfo.lastModified()); + } + }; - static QDnotifyFileSystemWatcherEngine *create(); + QHash<QString, FileInfo> files, directories; - void run(); +public: + QPollingFileSystemWatcherEngine(QObject *parent); QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); - void stop(); - private Q_SLOTS: - void refresh(int); + void timeout(); private: - struct Directory { - Directory() : fd(0), parentFd(0), isMonitored(false) {} - Directory(const Directory &o) : path(o.path), - fd(o.fd), - parentFd(o.parentFd), - isMonitored(o.isMonitored), - files(o.files) {} - QString path; - int fd; - int parentFd; - bool isMonitored; - - struct File { - File() : ownerId(0u), groupId(0u), permissions(0u) { } - File(const File &o) : path(o.path), - ownerId(o.ownerId), - groupId(o.groupId), - permissions(o.permissions), - lastWrite(o.lastWrite) {} - QString path; - - bool updateInfo(); - - uint ownerId; - uint groupId; - QFile::Permissions permissions; - QDateTime lastWrite; - }; - - QList<File> files; - }; - - QDnotifyFileSystemWatcherEngine(); - - QMutex mutex; - QHash<QString, int> pathToFD; - QHash<int, Directory> fdToDirectory; - QHash<int, int> parentToFD; + QTimer timer; }; +QT_END_NAMESPACE +#endif // QFILESYSTEMWATCHER_POLLING_P_H -QT_END_NAMESPACE -#endif // QT_NO_FILESYSTEMWATCHER -#endif // QFILESYSTEMWATCHER_DNOTIFY_P_H diff --git a/src/corelib/io/qfilesystemwatcher_symbian.cpp b/src/corelib/io/qfilesystemwatcher_symbian.cpp deleted file mode 100644 index 6e5e91114c..0000000000 --- a/src/corelib/io/qfilesystemwatcher_symbian.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qfilesystemwatcher.h" -#include "qfilesystemwatcher_symbian_p.h" -#include "qfileinfo.h" -#include "qdebug.h" -#include "private/qcore_symbian_p.h" -#include <QDir> - -#ifndef QT_NO_FILESYSTEMWATCHER - - -QT_BEGIN_NAMESPACE - -QNotifyChangeEvent::QNotifyChangeEvent(RFs &fs, const TDesC &file, - QSymbianFileSystemWatcherEngine *e, bool aIsDir, - TInt aPriority) : - CActive(aPriority), - isDir(aIsDir), - fsSession(fs), - watchedPath(file), - engine(e), - failureCount(0) -{ - if (isDir) { - fsSession.NotifyChange(ENotifyEntry, iStatus, file); - } else { - fsSession.NotifyChange(ENotifyAll, iStatus, file); - } - CActiveScheduler::Add(this); - SetActive(); -} - -QNotifyChangeEvent::~QNotifyChangeEvent() -{ - Cancel(); -} - -void QNotifyChangeEvent::RunL() -{ - if(iStatus.Int() == KErrNone) { - failureCount = 0; - } else { - qWarning("QNotifyChangeEvent::RunL() - Failed to order change notifications: %d", iStatus.Int()); - failureCount++; - } - - // Re-request failed notification once, but if it won't start working, - // we can't do much besides just not request any more notifications. - if (failureCount < 2) { - if (isDir) { - fsSession.NotifyChange(ENotifyEntry, iStatus, watchedPath); - } else { - fsSession.NotifyChange(ENotifyAll, iStatus, watchedPath); - } - SetActive(); - - if (!failureCount) { - int err; - QT_TRYCATCH_ERROR(err, engine->emitPathChanged(this)); - if (err != KErrNone) - qWarning("QNotifyChangeEvent::RunL() - emitPathChanged threw exception (Converted error code: %d)", err); - } - } -} - -void QNotifyChangeEvent::DoCancel() -{ - fsSession.NotifyChangeCancel(iStatus); -} - -QSymbianFileSystemWatcherEngine::QSymbianFileSystemWatcherEngine() : - watcherStarted(false) -{ - moveToThread(this); -} - -QSymbianFileSystemWatcherEngine::~QSymbianFileSystemWatcherEngine() -{ - stop(); -} - -QStringList QSymbianFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *files, - QStringList *directories) -{ - QMutexLocker locker(&mutex); - QStringList p = paths; - - startWatcher(); - - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - QFileInfo fi(path); - if (!fi.exists()) - continue; - - bool isDir = fi.isDir(); - if (isDir) { - if (directories->contains(path)) - continue; - } else { - if (files->contains(path)) - continue; - } - - // Use absolute filepath as relative paths seem to have some issues. - QString filePath = fi.absoluteFilePath(); - if (isDir && filePath.at(filePath.size() - 1) != QChar(L'/')) { - filePath += QChar(L'/'); - } - - currentAddEvent = NULL; - QMetaObject::invokeMethod(this, - "addNativeListener", - Qt::QueuedConnection, - Q_ARG(QString, filePath)); - - syncCondition.wait(&mutex); - if (currentAddEvent) { - currentAddEvent->isDir = isDir; - - activeObjectToPath.insert(currentAddEvent, path); - it.remove(); - - if (isDir) - directories->append(path); - else - files->append(path); - } - } - - return p; -} - -QStringList QSymbianFileSystemWatcherEngine::removePaths(const QStringList &paths, - QStringList *files, - QStringList *directories) -{ - QMutexLocker locker(&mutex); - - QStringList p = paths; - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - - currentRemoveEvent = activeObjectToPath.key(path); - if (!currentRemoveEvent) - continue; - activeObjectToPath.remove(currentRemoveEvent); - - QMetaObject::invokeMethod(this, - "removeNativeListener", - Qt::QueuedConnection); - - syncCondition.wait(&mutex); - - it.remove(); - - files->removeAll(path); - directories->removeAll(path); - } - - return p; -} - -void QSymbianFileSystemWatcherEngine::emitPathChanged(QNotifyChangeEvent *e) -{ - QMutexLocker locker(&mutex); - - QString path = activeObjectToPath.value(e); - QFileInfo fi(path); - - if (e->isDir) - emit directoryChanged(path, !fi.exists()); - else - emit fileChanged(path, !fi.exists()); -} - -void QSymbianFileSystemWatcherEngine::stop() -{ - quit(); - wait(); -} - -// This method must be called inside mutex -void QSymbianFileSystemWatcherEngine::startWatcher() -{ - if (!watcherStarted) { - setStackSize(0x5000); - start(); - syncCondition.wait(&mutex); - watcherStarted = true; - } -} - - -void QSymbianFileSystemWatcherEngine::run() -{ - mutex.lock(); - syncCondition.wakeOne(); - mutex.unlock(); - - exec(); - - foreach(QNotifyChangeEvent *e, activeObjectToPath.keys()) { - e->Cancel(); - delete e; - } - - activeObjectToPath.clear(); -} - -void QSymbianFileSystemWatcherEngine::addNativeListener(const QString &directoryPath) -{ - QMutexLocker locker(&mutex); - QString nativeDir(QDir::toNativeSeparators(directoryPath)); - TPtrC ptr(qt_QString2TPtrC(nativeDir)); - currentAddEvent = new QNotifyChangeEvent(qt_s60GetRFs(), ptr, this, directoryPath.endsWith(QChar(L'/'), Qt::CaseSensitive)); - syncCondition.wakeOne(); -} - -void QSymbianFileSystemWatcherEngine::removeNativeListener() -{ - QMutexLocker locker(&mutex); - currentRemoveEvent->Cancel(); - delete currentRemoveEvent; - currentRemoveEvent = NULL; - syncCondition.wakeOne(); -} - - -QT_END_NAMESPACE -#endif // QT_NO_FILESYSTEMWATCHER diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp index 4e94623844..e82a9a5b56 100644 --- a/src/corelib/io/qfilesystemwatcher_win.cpp +++ b/src/corelib/io/qfilesystemwatcher_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -50,25 +50,12 @@ #include <qset.h> #include <qdatetime.h> #include <qdir.h> +#include <qtextstream.h> QT_BEGIN_NAMESPACE -void QWindowsFileSystemWatcherEngine::stop() -{ - foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) - thread->stop(); -} - -QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine() - : QFileSystemWatcherEngine(false) -{ -} - QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine() { - if (threads.isEmpty()) - return; - foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) { thread->stop(); thread->wait(); @@ -310,7 +297,6 @@ QWindowsFileSystemWatcherEngineThread::QWindowsFileSystemWatcherEngineThread() handles.reserve(MAXIMUM_WAIT_OBJECTS); handles.append(h); } - moveToThread(this); } @@ -326,6 +312,17 @@ QWindowsFileSystemWatcherEngineThread::~QWindowsFileSystemWatcherEngineThread() } } +static inline QString msgFindNextFailed(const QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &pathInfos) +{ + QString result; + QTextStream str(&result); + str << "QFileSystemWatcher: FindNextChangeNotification failed for"; + foreach (const QWindowsFileSystemWatcherEngine::PathInfo &pathInfo, pathInfos) + str << " \"" << QDir::toNativeSeparators(pathInfo.absolutePath) << '"'; + str << ' '; + return result; +} + void QWindowsFileSystemWatcherEngineThread::run() { QMutexLocker locker(&mutex); @@ -356,11 +353,11 @@ void QWindowsFileSystemWatcherEngineThread::run() // for some reason, so we must check if the handle exist in the handles vector if (handles.contains(handle)) { // qDebug()<<"thread"<<this<<"Acknowledged handle:"<<at<<handle; + QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h = pathInfoForHandle[handle]; if (!FindNextChangeNotification(handle)) { - qErrnoWarning("QFileSystemWatcher: FindNextChangeNotification failed!!"); + const DWORD error = GetLastError(); + qErrnoWarning(error, "%s", qPrintable(msgFindNextFailed(h))); } - - QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h = pathInfoForHandle[handle]; QMutableHashIterator<QString, QWindowsFileSystemWatcherEngine::PathInfo> it(h); while (it.hasNext()) { QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo>::iterator x = it.next(); diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h index 3e9938a490..8e6b779b93 100644 --- a/src/corelib/io/qfilesystemwatcher_win_p.h +++ b/src/corelib/io/qfilesystemwatcher_win_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -60,6 +60,7 @@ #include <qt_windows.h> #include <QtCore/qdatetime.h> +#include <QtCore/qthread.h> #include <QtCore/qfile.h> #include <QtCore/qfileinfo.h> #include <QtCore/qhash.h> @@ -78,15 +79,14 @@ class QWindowsFileSystemWatcherEngine : public QFileSystemWatcherEngine { Q_OBJECT public: - QWindowsFileSystemWatcherEngine(); + inline QWindowsFileSystemWatcherEngine(QObject *parent) + : QFileSystemWatcherEngine(parent) + { } ~QWindowsFileSystemWatcherEngine(); QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); - void stop(); - - class Handle { public: diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 0d23a27909..a49ea84603 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfsfileengine.h b/src/corelib/io/qfsfileengine.h index 2e0b1eb923..0ed883a4a7 100644 --- a/src/corelib/io/qfsfileengine.h +++ b/src/corelib/io/qfsfileengine.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfsfileengine_iterator.cpp b/src/corelib/io/qfsfileengine_iterator.cpp index 323ab58335..2d162f6a7d 100644 --- a/src/corelib/io/qfsfileengine_iterator.cpp +++ b/src/corelib/io/qfsfileengine_iterator.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfsfileengine_iterator_p.h b/src/corelib/io/qfsfileengine_iterator_p.h index deccb01bfb..782930a52c 100644 --- a/src/corelib/io/qfsfileengine_iterator_p.h +++ b/src/corelib/io/qfsfileengine_iterator_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index 89c08aeca7..158c6f3a23 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 681e55dff7..b09518865e 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index f2b3e5f534..5dc96ea8a2 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -550,7 +550,7 @@ QString QFSFileEngine::currentPath(const QString &fileName) return ret; #else Q_UNUSED(fileName); - return QFileSystemEngine::currentPath(); + return QFileSystemEngine::currentPath().filePath(); #endif } @@ -661,6 +661,7 @@ bool QFSFileEngine::link(const QString &newName) #endif // QT_NO_LIBRARY #else QString linkName = newName; + linkName.replace(QLatin1Char('/'), QLatin1Char('\\')); if (!linkName.endsWith(QLatin1String(".lnk"))) linkName += QLatin1String(".lnk"); QString orgName = fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')); diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 8e1b2d5d0c..ef530f379f 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qiodevice.h b/src/corelib/io/qiodevice.h index 7d4afca850..4b34ad4f69 100644 --- a/src/corelib/io/qiodevice.h +++ b/src/corelib/io/qiodevice.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h index 3ccad6254a..2515fe5705 100644 --- a/src/corelib/io/qiodevice_p.h +++ b/src/corelib/io/qiodevice_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp index 113ba4b4bb..ba711493c6 100644 --- a/src/corelib/io/qnoncontiguousbytedevice.cpp +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h index c7c94243b9..ded605681e 100644 --- a/src/corelib/io/qnoncontiguousbytedevice_p.h +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index d2aee16c45..8f76e0e4b9 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -471,7 +471,7 @@ void QProcessPrivate::Channel::clear() read the standard output by calling read(), readLine(), and getChar(). Because it inherits QIODevice, QProcess can also be used as an input source for QXmlReader, or for generating data to - be uploaded using QFtp. + be uploaded using QNetworkAccessManager. \note On Windows CE and Symbian, reading and writing to a process is not supported. @@ -617,6 +617,14 @@ void QProcessPrivate::Channel::clear() writes to its standard output and standard error will be written to the standard output and standard error of the main process. + \note Windows intentionally suppresses output from GUI-only + applications to inherited consoles. + This does \e not apply to output redirected to files or pipes. + To forward the output of GUI-only applications on the console + nonetheless, you must use SeparateChannels and do the forwarding + yourself by reading the output and writing it to the appropriate + output channels. + \sa setProcessChannelMode() */ @@ -2271,7 +2279,7 @@ QT_END_INCLUDE_NAMESPACE However, note that repeated calls to this function will recreate the list of environment variables, which is a non-trivial operation. - \note For new code, it is recommended to use QProcessEvironment::systemEnvironment() + \note For new code, it is recommended to use QProcessEnvironment::systemEnvironment() \sa QProcessEnvironment::systemEnvironment(), environment(), setEnvironment() */ diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index b2a5a4cbff..96a1edefd8 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 5bebff089e..7e0fecc320 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qprocess_symbian.cpp b/src/corelib/io/qprocess_symbian.cpp deleted file mode 100644 index 9fd0c3aa65..0000000000 --- a/src/corelib/io/qprocess_symbian.cpp +++ /dev/null @@ -1,1072 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -//#define QPROCESS_DEBUG - -#ifdef QPROCESS_DEBUG -#include "qdebug.h" -#define QPROCESS_DEBUG_PRINT(args...) qDebug(args); -#else -#define QPROCESS_DEBUG_PRINT(args...) -#endif - -#ifndef QT_NO_PROCESS - -#define QPROCESS_ASSERT(check, panicReason, args...) \ - if (!(check)) { \ - qWarning(args); \ - User::Panic(KQProcessPanic, panicReason); \ - } - -#include <exception> -#include <e32base.h> -#include <e32std.h> -#include <stdio.h> -#include "qplatformdefs.h" - -#include "qdir.h" -#include "qstring.h" -#include "qprocess.h" -#include "qprocess_p.h" -#include "private/qeventdispatcher_symbian_p.h" - -#include <private/qthread_p.h> -#include <qmutex.h> -#include <qmap.h> -#include <qsocketnotifier.h> - -#include <errno.h> - - -QT_BEGIN_NAMESPACE - -_LIT(KQProcessManagerThreadName, "QProcManThread"); -_LIT(KQProcessPanic, "QPROCESS"); -enum TQProcessPanic { - EProcessManagerMediatorRunError = 1, - EProcessManagerMediatorInactive = 2, - EProcessManagerMediatorNotPending = 3, - EProcessManagerMediatorInvalidCmd = 4, - EProcessManagerMediatorCreationFailed = 5, - EProcessManagerMediatorThreadOpenFailed = 6, - EProcessManagerMediatorNullObserver = 7, - EProcessActiveRunError = 10, - EProcessActiveNullParameter = 11, - EProcessManagerMutexCreationFail = 20, - EProcessManagerThreadCreationFail = 21, - EProcessManagerSchedulerCreationFail = 22, - EProcessManagerNullParam = 23 -}; - -// Forward declarations -class QProcessManager; - - -// Active object to listen for child process death -class QProcessActive : public CActive -{ -public: - static QProcessActive *construct(QProcess *process, - RProcess **proc, - int serial, - int deathPipe); - - virtual ~QProcessActive(); - - void start(); - void stop(); - - bool error(); - -protected: - - // Inherited from CActive - void RunL(); - TInt RunError(TInt aError); - void DoCancel(); - - QProcessActive(); - -private: - - QProcess *process; - RProcess **pproc; - int serial; - int deathPipe; - bool errorValue; -}; - -// Active object to communicate synchronously with process manager thread -class QProcessManagerMediator : public CActive -{ -public: - static QProcessManagerMediator *construct(); - - virtual ~QProcessManagerMediator(); - - bool add(QProcessActive *processObserver); - void remove(QProcessActive *processObserver); - void terminate(); - -protected: - - enum Commands { - ENoCommand, - EAdd, - ERemove, - ETerminate - }; - - // Inherited from CActive - void RunL(); - TInt RunError(TInt aError); - void DoCancel(); - - QProcessManagerMediator(); - - bool notify(QProcessActive *processObserver, Commands command); - -private: - QProcessActive *currentObserver; - Commands currentCommand; - - RThread processManagerThread; -}; - -// Process manager manages child process death listeners. -// -// Note: Because QProcess can be used outside event loop, we cannot be guaranteed -// an active scheduler exists for us to add our process death listener objects. -// We can't just install active scheduler on the calling thread, as that would block it -// if we want to actually use it, so a separate manager thread is required. -class QProcessManager -{ -public: - QProcessManager(); - ~QProcessManager(); - - void startThread(); - - TInt run(void *param); - bool add(QProcess *process); - void remove(QProcess *process); - - inline void setMediator(QProcessManagerMediator *newMediator) { - mediator = newMediator; - }; - -private: - inline void lock() { - managerMutex.Wait(); - }; - inline void unlock() { - managerMutex.Signal(); - }; - - QMap<int, QProcessActive *> children; - QProcessManagerMediator *mediator; - RMutex managerMutex; - bool threadStarted; - RThread managerThread; -}; - -static bool qt_rprocess_running(RProcess *proc) -{ - if (proc && proc->Handle()) { - TExitType et = proc->ExitType(); - if (et == EExitPending) - return true; - } - - return false; -} - -static void qt_create_symbian_commandline( - const QStringList &arguments, const QString &nativeArguments, QString &commandLine) -{ - for (int i = 0; i < arguments.size(); ++i) { - QString tmp = arguments.at(i); - // in the case of \" already being in the string the \ must also be escaped - tmp.replace(QLatin1String("\\\""), QLatin1String("\\\\\"")); - // escape a single " because the arguments will be parsed - tmp.replace(QLatin1String("\""), QLatin1String("\\\"")); - if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) { - // The argument must not end with a \ since this would be interpreted - // as escaping the quote -- rather put the \ behind the quote: e.g. - // rather use "foo"\ than "foo\" - QString endQuote(QLatin1String("\"")); - int i = tmp.length(); - while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\')) { - --i; - endQuote += QLatin1String("\\"); - } - commandLine += QLatin1String("\"") + tmp.left(i) + endQuote + QLatin1Char(' '); - } else { - commandLine += tmp + QLatin1Char(' '); - } - } - - if (!nativeArguments.isEmpty()) - commandLine += nativeArguments; - else if (!commandLine.isEmpty()) // Chop the extra trailing space if any arguments were appended - commandLine.chop(1); -} - -static TInt qt_create_symbian_process(RProcess **proc, - const QString &programName, const QStringList &arguments, const QString &nativeArguments) -{ - RProcess *newProc = NULL; - newProc = new RProcess(); - - if (!newProc) - return KErrNoMemory; - - QString commandLine; - qt_create_symbian_commandline(arguments, nativeArguments, commandLine); - - TPtrC program_ptr(reinterpret_cast<const TText*>(programName.constData())); - TPtrC cmdline_ptr(reinterpret_cast<const TText*>(commandLine.constData())); - - TInt err = newProc->Create(program_ptr, cmdline_ptr); - - if (err == KErrNotFound) { - // Strip path from program name and try again (i.e. try from default location "\sys\bin") - int index = programName.lastIndexOf(QDir::separator()); - int index2 = programName.lastIndexOf(QChar(QLatin1Char('/'))); - index = qMax(index, index2); - - if (index != -1 && programName.length() >= index) { - QString strippedName; - strippedName = programName.mid(index + 1); - QPROCESS_DEBUG_PRINT("qt_create_symbian_process() Executable '%s' not found, trying stripped version '%s'", - qPrintable(programName), qPrintable(strippedName)); - - TPtrC stripped_ptr(reinterpret_cast<const TText*>(strippedName.constData())); - err = newProc->Create(stripped_ptr, cmdline_ptr); - - if (err != KErrNone) { - QPROCESS_DEBUG_PRINT("qt_create_symbian_process() Unable to create process '%s': %d", - qPrintable(strippedName), err); - } - } - } - - if (err == KErrNone) - *proc = newProc; - else - delete newProc; - - return err; -} - -static qint64 qt_native_read(int fd, char *data, qint64 maxlen) -{ - qint64 ret = 0; - do { - ret = ::read(fd, data, maxlen); - } while (ret == -1 && errno == EINTR); - - QPROCESS_DEBUG_PRINT("qt_native_read(): fd: %d, result: %d, errno = %d", fd, (int)ret, errno); - - return ret; -} - -static qint64 qt_native_write(int fd, const char *data, qint64 len) -{ - qint64 ret = 0; - do { - ret = ::write(fd, data, len); - } while (ret == -1 && errno == EINTR); - - QPROCESS_DEBUG_PRINT("qt_native_write(): fd: %d, result: %d, errno = %d", fd, (int)ret, errno); - - return ret; -} - -static void qt_native_close(int fd) -{ - int ret; - do { - ret = ::close(fd); - } while (ret == -1 && errno == EINTR); -} - -static void qt_create_pipe(int *pipe) -{ - if (pipe[0] != -1) - qt_native_close(pipe[0]); - if (pipe[1] != -1) - qt_native_close(pipe[1]); - if (::pipe(pipe) != 0) { - qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s", - pipe, qPrintable(qt_error_string(errno))); - } else { - QPROCESS_DEBUG_PRINT("qt_create_pipe(): Created pipe %d - %d", pipe[0], pipe[1]); - } -} - -// Called from ProcessManagerThread -QProcessActive *QProcessActive::construct(QProcess *process, - RProcess **proc, - int serial, - int deathPipe) -{ - QPROCESS_ASSERT((process || proc || *proc), - EProcessActiveNullParameter, - "QProcessActive::construct(): process (0x%x), proc (0x%x) or *proc == NULL, not creating an instance", process, proc) - - QProcessActive *newInstance = new QProcessActive(); - - if (!newInstance) { - QPROCESS_DEBUG_PRINT("QProcessActive::construct(): Failed to create new instance"); - } else { - newInstance->process = process; - newInstance->pproc = proc; - newInstance->serial = serial; - newInstance->deathPipe = deathPipe; - newInstance->errorValue = false; - } - - return newInstance; -} - -// Called from ProcessManagerThread -QProcessActive::QProcessActive() - : CActive(CActive::EPriorityStandard) -{ - // Nothing to do -} - -// Called from main thread -QProcessActive::~QProcessActive() -{ - process = NULL; - pproc = NULL; -} - -// Called from ProcessManagerThread -void QProcessActive::start() -{ - if (qt_rprocess_running(*pproc)) { - CActiveScheduler::Add(this); - (*pproc)->Logon(iStatus); - SetActive(); - QPROCESS_DEBUG_PRINT("QProcessActive::start(): Started monitoring for process exit."); - } else { - QPROCESS_DEBUG_PRINT("QProcessActive::start(): Process doesn't exist or is already dead"); - // Assume process has already died - qt_native_write(deathPipe, "", 1); - errorValue = true; - } -} - -// Called from ProcessManagerThread -void QProcessActive::stop() -{ - QPROCESS_DEBUG_PRINT("QProcessActive::stop()"); - - // Remove this from scheduler (also cancels the request) - Deque(); -} - -bool QProcessActive::error() -{ - return errorValue; -} - -// Called from ProcessManagerThread -void QProcessActive::RunL() -{ - // If this method gets executed, the monitored process has died - - // Notify main thread - qt_native_write(deathPipe, "", 1); - QPROCESS_DEBUG_PRINT("QProcessActive::RunL() sending death notice to %d", deathPipe); -} - -// Called from ProcessManagerThread -TInt QProcessActive::RunError(TInt aError) -{ - Q_UNUSED(aError); - // Handle RunL leave (should never happen) - QPROCESS_ASSERT(0, EProcessActiveRunError, "QProcessActive::RunError(): Should never get here!") - return 0; -} - -// Called from ProcessManagerThread -void QProcessActive::DoCancel() -{ - QPROCESS_DEBUG_PRINT("QProcessActive::DoCancel()"); - - if (qt_rprocess_running(*pproc)) { - (*pproc)->LogonCancel(iStatus); - QPROCESS_DEBUG_PRINT("QProcessActive::DoCancel(): Stopped monitoring for process exit."); - } else { - QPROCESS_DEBUG_PRINT("QProcessActive::DoCancel(): Process doesn't exist"); - } -} - - -// Called from ProcessManagerThread -QProcessManagerMediator *QProcessManagerMediator::construct() -{ - QProcessManagerMediator *newInstance = new QProcessManagerMediator; - TInt err(KErrNone); - - newInstance->currentCommand = ENoCommand; - newInstance->currentObserver = NULL; - - if (newInstance) { - err = newInstance->processManagerThread.Open(newInstance->processManagerThread.Id()); - QPROCESS_ASSERT((err == KErrNone), - EProcessManagerMediatorThreadOpenFailed, - "QProcessManagerMediator::construct(): Failed to open processManagerThread (err:%d)", err) - } else { - QPROCESS_ASSERT(0, - EProcessManagerMediatorCreationFailed, - "QProcessManagerMediator::construct(): Failed to open construct mediator") - } - - // Activate mediator - CActiveScheduler::Add(newInstance); - newInstance->iStatus = KRequestPending; - newInstance->SetActive(); - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::construct(): new instance successfully created and activated"); - - return newInstance; -} - -// Called from ProcessManagerThread -QProcessManagerMediator::QProcessManagerMediator() - : CActive(CActive::EPriorityStandard) -{ - // Nothing to do -} - -// Called from main thread -QProcessManagerMediator::~QProcessManagerMediator() -{ - processManagerThread.Close(); - currentCommand = ENoCommand; - currentObserver = NULL; -} - -// Called from main thread -bool QProcessManagerMediator::add(QProcessActive *processObserver) -{ - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::add()"); - return notify(processObserver, EAdd); -} - -// Called from main thread -void QProcessManagerMediator::remove(QProcessActive *processObserver) -{ - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::remove()"); - notify(processObserver, ERemove); -} - -// Called from main thread -void QProcessManagerMediator::terminate() -{ - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::terminate()"); - notify(NULL, ETerminate); -} - -// Called from main thread -bool QProcessManagerMediator::notify(QProcessActive *processObserver, Commands command) -{ - bool success(true); - - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::Notify(): Command: %d, processObserver: 0x%x", command, processObserver); - - QPROCESS_ASSERT((command == ETerminate || processObserver), - EProcessManagerMediatorNullObserver, - "QProcessManagerMediator::Notify(): NULL processObserver not allowed for command: %d", command) - - QPROCESS_ASSERT(IsActive(), - EProcessManagerMediatorInactive, - "QProcessManagerMediator::Notify(): Mediator is not active!") - - QPROCESS_ASSERT(iStatus == KRequestPending, - EProcessManagerMediatorNotPending, - "QProcessManagerMediator::Notify(): Mediator request not pending!") - - currentObserver = processObserver; - currentCommand = command; - - // Sync with process manager thread - TRequestStatus pmStatus; - processManagerThread.Rendezvous(pmStatus); - - // Complete request -> RunL will run in the process manager thread - TRequestStatus *status = &iStatus; - processManagerThread.RequestComplete(status, command); - - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::Notify(): Waiting process manager to complete..."); - User::WaitForRequest(pmStatus); - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::Notify(): Wait over"); - - if (currentObserver) { - success = !(currentObserver->error()); - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::Notify(): success = %d", success); - } - - currentObserver = NULL; - currentCommand = ENoCommand; - - return success; -} - -// Called from ProcessManagerThread -void QProcessManagerMediator::RunL() -{ - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::RunL(): currentCommand: %d, iStatus: %d", currentCommand, iStatus.Int()); - switch (currentCommand) { - case EAdd: - currentObserver->start(); - break; - case ERemove: - currentObserver->stop(); - break; - case ETerminate: - Deque(); - CActiveScheduler::Stop(); - return; - default: - QPROCESS_ASSERT(0, - EProcessManagerMediatorInvalidCmd, - "QProcessManagerMediator::RunL(): Invalid command!") - break; - } - - iStatus = KRequestPending; - SetActive(); - - // Notify main thread that we are done - RThread::Rendezvous(KErrNone); -} - -// Called from ProcessManagerThread -TInt QProcessManagerMediator::RunError(TInt aError) -{ - Q_UNUSED(aError); - // Handle RunL leave (should never happen) - QPROCESS_ASSERT(0, - EProcessManagerMediatorRunError, - "QProcessManagerMediator::RunError(): Should never get here!") - return 0; -} - -// Called from ProcessManagerThread -void QProcessManagerMediator::DoCancel() -{ - QPROCESS_DEBUG_PRINT("QProcessManagerMediator::DoCancel()"); - TRequestStatus *status = &iStatus; - processManagerThread.RequestComplete(status, KErrCancel); -} - -Q_GLOBAL_STATIC(QProcessManager, processManager) - -TInt processManagerThreadFunction(TAny *param) -{ - QPROCESS_ASSERT(param, - EProcessManagerNullParam, - "processManagerThreadFunction(): NULL param") - - QProcessManager *manager = reinterpret_cast<QProcessManager*>(param); - - CActiveScheduler *scheduler = new CQtActiveScheduler(); - - QPROCESS_ASSERT(scheduler, - EProcessManagerSchedulerCreationFail, - "processManagerThreadFunction(): Scheduler creation failed") - - CActiveScheduler::Install(scheduler); - - //Creating mediator also adds it to scheduler and activates it. Failure will panic. - manager->setMediator(QProcessManagerMediator::construct()); - RThread::Rendezvous(KErrNone); - - CActiveScheduler::Start(); - - CActiveScheduler::Install(NULL); - delete scheduler; - - return KErrNone; -} - -QProcessManager::QProcessManager() - : mediator(NULL), threadStarted(false) -{ - TInt err = managerMutex.CreateLocal(); - - QPROCESS_ASSERT(err == KErrNone, - EProcessManagerMutexCreationFail, - "QProcessManager::QProcessManager(): Failed to create new managerMutex (err: %d)", err) -} - -QProcessManager::~QProcessManager() -{ - QPROCESS_DEBUG_PRINT("QProcessManager::~QProcessManager()"); - - // Check if manager thread is still alive. If this destructor is ran as part of global - // static cleanup, manager thread will most likely be terminated by kernel at this point, - // so trying to delete QProcessActives and QProcessMediators will panic as they - // will still be active. They can also no longer be canceled as the thread is already gone. - // In case manager thread has already died, we simply do nothing and let the deletion of - // the main heap at process exit take care of stray objects. - - if (managerThread.Handle() && managerThread.ExitType() == EExitPending) { - // Cancel death listening for all child processes - if (mediator) { - QMap<int, QProcessActive *>::Iterator it = children.begin(); - while (it != children.end()) { - // Remove all monitors - QProcessActive *active = it.value(); - mediator->remove(active); - - QPROCESS_DEBUG_PRINT("QProcessManager::~QProcessManager() removed listening for a process"); - ++it; - } - - // Terminate process manager thread. - mediator->terminate(); - delete mediator; - } - - qDeleteAll(children.values()); - children.clear(); - } - - managerThread.Close(); - managerMutex.Close(); -} - -void QProcessManager::startThread() -{ - lock(); - - if (!threadStarted) { - TInt err = managerThread.Create(KQProcessManagerThreadName, - processManagerThreadFunction, - 0x5000, - (RAllocator*)NULL, - (TAny*)this, - EOwnerProcess); - - QPROCESS_ASSERT(err == KErrNone, - EProcessManagerThreadCreationFail, - "QProcessManager::startThread(): Failed to create new managerThread (err:%d)", err) - - threadStarted = true; - - // Manager thread must start running before we continue, so sync with rendezvous - TRequestStatus status; - managerThread.Rendezvous(status); - managerThread.Resume(); - User::WaitForRequest(status); - } - - unlock(); -} - -static QBasicAtomicInt idCounter = Q_BASIC_ATOMIC_INITIALIZER(1); - -bool QProcessManager::add(QProcess *process) -{ - QPROCESS_ASSERT(process, - EProcessManagerNullParam, - "QProcessManager::add(): Failed to add QProcessActive to ProcessManager - NULL process") - - lock(); - - int serial = idCounter.fetchAndAddRelaxed(1); - process->d_func()->serial = serial; - - QPROCESS_DEBUG_PRINT("QProcessManager::add(): serial: %d, deathPipe: %d - %d, symbianProcess: 0x%x", serial, process->d_func()->deathPipe[0], process->d_func()->deathPipe[1], process->d_func()->symbianProcess); - - QProcessActive *newActive = - QProcessActive::construct(process, - &(process->d_func()->symbianProcess), - serial, - process->d_func()->deathPipe[1]); - - if (newActive) { - if (mediator->add(newActive)) { - children.insert(serial, newActive); - unlock(); - return true; - } else { - QPROCESS_DEBUG_PRINT("QProcessManager::add(): Failed to add QProcessActive to ProcessManager"); - delete newActive; - } - } - - unlock(); - - return false; -} - -void QProcessManager::remove(QProcess *process) -{ - QPROCESS_ASSERT(process, - EProcessManagerNullParam, - "QProcessManager::remove(): Failed to remove QProcessActive from ProcessManager - NULL process") - - lock(); - - int serial = process->d_func()->serial; - QProcessActive *active = children.value(serial); - if (!active) { - unlock(); - return; - } - - mediator->remove(active); - - children.remove(serial); - delete active; - - unlock(); -} - -void QProcessPrivate::destroyPipe(int *pipe) -{ - if (pipe[1] != -1) { - qt_native_close(pipe[1]); - pipe[1] = -1; - } - if (pipe[0] != -1) { - qt_native_close(pipe[0]); - pipe[0] = -1; - } -} - -bool QProcessPrivate::createChannel(Channel &channel) -{ - Q_UNUSED(channel); - // No channels used - return false; -} - -void QProcessPrivate::startProcess() -{ - Q_Q(QProcess); - - QPROCESS_DEBUG_PRINT("QProcessPrivate::startProcess()"); - - // Start the process (platform dependent) - q->setProcessState(QProcess::Starting); - - processManager()->startThread(); - - qt_create_pipe(deathPipe); - if (threadData->eventDispatcher) { - deathNotifier = new QSocketNotifier(deathPipe[0], - QSocketNotifier::Read, q); - QObject::connect(deathNotifier, SIGNAL(activated(int)), - q, SLOT(_q_processDied())); - } - - TInt err = qt_create_symbian_process(&symbianProcess, program, arguments, nativeArguments); - - if (err == KErrNone) { - pid = symbianProcess->Id().Id(); - - ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK); - - if (!processManager()->add(q)) { - qWarning("QProcessPrivate::startProcess(): Failed to start monitoring for process death."); - err = KErrNoMemory; - } - } - - if (err != KErrNone) { - // Cleanup, report error and return - QPROCESS_DEBUG_PRINT("QProcessPrivate::startProcess() Process open failed, err: %d, '%s'", err, qPrintable(program)); - q->setProcessState(QProcess::NotRunning); - processError = QProcess::FailedToStart; - q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Resource error (qt_create_symbian_process failure)"))); - emit q->error(processError); - cleanup(); - return; - } - - processLaunched = true; - - symbianProcess->Resume(); - - QPROCESS_DEBUG_PRINT("QProcessPrivate::startProcess(): this: 0x%x, pid: %ld", this, pid); - - // Notify child start - _q_startupNotification(); - -} - -bool QProcessPrivate::processStarted() -{ - QPROCESS_DEBUG_PRINT("QProcessPrivate::processStarted() == %s", processLaunched ? "true" : "false"); - - // Since we cannot get information whether process has actually been launched - // or not in Symbian, we need to fake it. Assume process is started if launch was - // successful. - - return processLaunched; -} - -qint64 QProcessPrivate::bytesAvailableFromStdout() const -{ - // In Symbian, stdout is not supported - return 0; -} - -qint64 QProcessPrivate::bytesAvailableFromStderr() const -{ - // In Symbian, stderr is not supported - return 0; -} - -qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen) -{ - Q_UNUSED(data); - Q_UNUSED(maxlen); - // In Symbian, stdout is not supported - return 0; -} - -qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen) -{ - Q_UNUSED(data); - Q_UNUSED(maxlen); - // In Symbian, stderr is not supported - return 0; -} - -qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen) -{ - Q_UNUSED(data); - Q_UNUSED(maxlen); - // In Symbian, stdin is not supported - return 0; -} - -void QProcessPrivate::terminateProcess() -{ - // Needs PowerMgmt capability if process has been started; will panic kern-exec 46 otherwise. - // Always works if process is not yet started. - if (qt_rprocess_running(symbianProcess)) { - symbianProcess->Terminate(0); - } else { - QPROCESS_DEBUG_PRINT("QProcessPrivate::terminateProcess(), Process not running"); - } -} - -void QProcessPrivate::killProcess() -{ - // Needs PowerMgmt capability if process has been started; will panic kern-exec 46 otherwise. - // Always works if process is not yet started. - if (qt_rprocess_running(symbianProcess)) { - symbianProcess->Kill(0); - } else { - QPROCESS_DEBUG_PRINT("QProcessPrivate::killProcess(), Process not running"); - } -} - -bool QProcessPrivate::waitForStarted(int msecs) -{ - Q_UNUSED(msecs); - // Since we can get no actual feedback from process beyond its death, - // assume that started has already been emitted if process has been launched - return processLaunched; -} - -bool QProcessPrivate::waitForReadyRead(int msecs) -{ - // Functionality not supported in Symbian - Q_UNUSED(msecs); - return false; -} - -bool QProcessPrivate::waitForBytesWritten(int msecs) -{ - // Functionality not supported in Symbian - Q_UNUSED(msecs); - return false; -} - -bool QProcessPrivate::waitForFinished(int msecs) -{ - Q_Q(QProcess); - QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished(%d)", msecs); - - TRequestStatus timerStatus = KErrNone; - TRequestStatus logonStatus = KErrNone; - bool timeoutOccurred = false; - - // Logon to process to observe its death - if (qt_rprocess_running(symbianProcess)) { - symbianProcess->Logon(logonStatus); - - if (msecs < 0) { - // If timeout is negative, there is no timeout - QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished() - Waiting (just logon)..."); - User::WaitForRequest(logonStatus); - QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished() - Wait completed"); - } else { - // Create timer - RTimer timer; - timer.CreateLocal(); - TTimeIntervalMicroSeconds32 interval(msecs*1000); - timer.After(timerStatus, interval); - - QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished() - Waiting (logon + timer)..."); - User::WaitForRequest(logonStatus, timerStatus); - QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished() - Wait completed"); - - if (logonStatus != KRequestPending) { - timer.Cancel(); - User::WaitForRequest(timerStatus); - } else { - timeoutOccurred = true; - symbianProcess->LogonCancel(logonStatus); - User::WaitForRequest(logonStatus); - } - timer.Close(); - } - } else { - QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished(), qt_rprocess_running returned false"); - } - - if (timeoutOccurred) { - processError = QProcess::Timedout; - q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Process operation timed out"))); - return false; - } - - _q_processDied(); - - return true; -} - -bool QProcessPrivate::waitForWrite(int msecs) -{ - // Functionality not supported in Symbian - Q_UNUSED(msecs); - return false; -} - -// Deceptively named function. Exit code is actually got in waitForDeadChild(). -void QProcessPrivate::findExitCode() -{ - Q_Q(QProcess); - processManager()->remove(q); -} - -bool QProcessPrivate::waitForDeadChild() -{ - Q_Q(QProcess); - - // read a byte from the death pipe - char c; - qt_native_read(deathPipe[0], &c, 1); - - if (symbianProcess && symbianProcess->Handle()) { - TExitType et = symbianProcess->ExitType(); - QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForDeadChild() symbianProcess->ExitType: %d", et); - if (et != EExitPending) { - processManager()->remove(q); - exitCode = symbianProcess->ExitReason(); - crashed = (et == EExitPanic); -#if defined QPROCESS_DEBUG - TExitCategoryName catName = symbianProcess->ExitCategory(); - qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode" - << exitCode << ", crashed:" << crashed - << ", category:" << QString((const QChar *)catName.Ptr()); -#endif - } else { - QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForDeadChild() not dead!"); - } - } - - return true; -} - -void QProcessPrivate::_q_notified() -{ - // Nothing to do in Symbian -} - -bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) -{ - QPROCESS_DEBUG_PRINT("QProcessPrivate::startDetached()"); - Q_UNUSED(workingDirectory); - - RProcess *newProc = NULL; - - TInt err = qt_create_symbian_process(&newProc, program, arguments, QString()); - - if (err == KErrNone) { - if (pid) - *pid = newProc->Id().Id(); - - newProc->Resume(); - newProc->Close(); - delete newProc; - return true; - } - - return false; -} - - -void QProcessPrivate::initializeProcessManager() -{ - (void) processManager(); -} - -QProcessEnvironment QProcessEnvironment::systemEnvironment() -{ - return QProcessEnvironment(); -} - -QT_END_NAMESPACE - -#endif // QT_NO_PROCESS diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 5fc69ed2cd..f01df3c078 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index d47e55dee4..8c6444d173 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -72,7 +72,6 @@ static void qt_create_pipe(Q_PIPE *pipe, bool in) // read handles to avoid non-closable handles (this is done by the // DuplicateHandle() call). -#if !defined(Q_OS_WINCE) SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE }; HANDLE tmpHandle; @@ -91,10 +90,15 @@ static void qt_create_pipe(Q_PIPE *pipe, bool in) } CloseHandle(tmpHandle); -#else - Q_UNUSED(pipe); - Q_UNUSED(in); -#endif +} + +static void duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle) +{ + pipe[0] = INVALID_Q_PIPE; + HANDLE hStdWriteChannel = GetStdHandle(nStdHandle); + HANDLE hCurrentProcess = GetCurrentProcess(); + DuplicateHandle(hCurrentProcess, hStdWriteChannel, hCurrentProcess, + &pipe[1], 0, TRUE, DUPLICATE_SAME_ACCESS); } /* @@ -113,8 +117,11 @@ bool QProcessPrivate::createChannel(Channel &channel) if (channel.type == Channel::Normal) { // we're piping this channel to our own process - qt_create_pipe(channel.pipe, &channel == &stdinChannel); - + const bool isStdInChannel = (&channel == &stdinChannel); + if (isStdInChannel || processChannelMode != QProcess::ForwardedChannels) + qt_create_pipe(channel.pipe, isStdInChannel); + else + duplicateStdWriteChannel(channel.pipe, (&channel == &stdoutChannel) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); return true; } else if (channel.type == Channel::Redirect) { // we're redirecting the channel to/from a file @@ -277,7 +284,6 @@ static QString qt_create_commandline(const QString &program, const QStringList & QProcessEnvironment QProcessEnvironment::systemEnvironment() { QProcessEnvironment env; -#if !defined(Q_OS_WINCE) // Calls to setenv() affect the low-level environment as well. // This is not the case the other way round. if (wchar_t *envStrings = GetEnvironmentStringsW()) { @@ -293,11 +299,9 @@ QProcessEnvironment QProcessEnvironment::systemEnvironment() } FreeEnvironmentStringsW(envStrings); } -#endif return env; } -#if !defined(Q_OS_WINCE) static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Hash &environment) { QByteArray envlist; @@ -357,7 +361,6 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Hash & } return envlist; } -#endif void QProcessPrivate::startProcess() { @@ -381,14 +384,10 @@ void QProcessPrivate::startProcess() !createChannel(stderrChannel)) return; -#if defined(Q_OS_WINCE) - QString args = qt_create_commandline(QString(), arguments); -#else QString args = qt_create_commandline(program, arguments); QByteArray envlist; if (environment.d.constData()) envlist = qt_create_environment(environment.d.constData()->hash); -#endif if (!nativeArguments.isEmpty()) { if (!args.isEmpty()) args += QLatin1Char(' '); @@ -402,15 +401,6 @@ void QProcessPrivate::startProcess() qDebug(" pass environment : %s", environment.isEmpty() ? "no" : "yes"); #endif -#if defined(Q_OS_WINCE) - QString fullPathProgram = program; - if (!QDir::isAbsolutePath(fullPathProgram)) - fullPathProgram = QFileInfo(fullPathProgram).absoluteFilePath(); - fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\')); - success = CreateProcess((wchar_t*)fullPathProgram.utf16(), - (wchar_t*)args.utf16(), - 0, 0, false, 0, 0, 0, 0, pid); -#else DWORD dwCreationFlags = CREATE_NO_WINDOW; dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, @@ -443,7 +433,6 @@ void QProcessPrivate::startProcess() CloseHandle(stderrChannel.pipe[1]); stderrChannel.pipe[1] = INVALID_Q_PIPE; } -#endif // Q_OS_WINCE if (!success) { cleanup(); @@ -484,24 +473,10 @@ qint64 QProcessPrivate::bytesAvailableFromStdout() const return 0; DWORD bytesAvail = 0; -#if !defined(Q_OS_WINCE) PeekNamedPipe(stdoutChannel.pipe[0], 0, 0, 0, &bytesAvail, 0); #if defined QPROCESS_DEBUG qDebug("QProcessPrivate::bytesAvailableFromStdout() == %d", bytesAvail); #endif - if (processChannelMode == QProcess::ForwardedChannels && bytesAvail > 0) { - QByteArray buf(bytesAvail, 0); - DWORD bytesRead = 0; - if (ReadFile(stdoutChannel.pipe[0], buf.data(), buf.size(), &bytesRead, 0) && bytesRead > 0) { - HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - if (hStdout) { - DWORD bytesWritten = 0; - WriteFile(hStdout, buf.data(), bytesRead, &bytesWritten, 0); - } - } - bytesAvail = 0; - } -#endif return bytesAvail; } @@ -511,24 +486,10 @@ qint64 QProcessPrivate::bytesAvailableFromStderr() const return 0; DWORD bytesAvail = 0; -#if !defined(Q_OS_WINCE) PeekNamedPipe(stderrChannel.pipe[0], 0, 0, 0, &bytesAvail, 0); #if defined QPROCESS_DEBUG qDebug("QProcessPrivate::bytesAvailableFromStderr() == %d", bytesAvail); #endif - if (processChannelMode == QProcess::ForwardedChannels && bytesAvail > 0) { - QByteArray buf(bytesAvail, 0); - DWORD bytesRead = 0; - if (ReadFile(stderrChannel.pipe[0], buf.data(), buf.size(), &bytesRead, 0) && bytesRead > 0) { - HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); - if (hStderr) { - DWORD bytesWritten = 0; - WriteFile(hStderr, buf.data(), bytesRead, &bytesWritten, 0); - } - } - bytesAvail = 0; - } -#endif return bytesAvail; } @@ -596,13 +557,6 @@ bool QProcessPrivate::waitForReadyRead(int msecs) { Q_Q(QProcess); -#if defined(Q_OS_WINCE) - processError = QProcess::ReadError; - q->setErrorString(QProcess::tr("Error reading from process")); - emit q->error(processError); - return false; -#endif - QIncrementalSleepTimer timer(msecs); forever { @@ -646,13 +600,6 @@ bool QProcessPrivate::waitForBytesWritten(int msecs) { Q_Q(QProcess); -#if defined(Q_OS_WINCE) - processError = QProcess::ReadError; - q->setErrorString(QProcess::tr("Error reading from process")); - emit q->error(processError); - return false; -#endif - QIncrementalSleepTimer timer(msecs); forever { @@ -786,13 +733,6 @@ qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen) { Q_Q(QProcess); -#if defined(Q_OS_WINCE) - processError = QProcess::WriteError; - q->setErrorString(QProcess::tr("Error writing to process")); - emit q->error(processError); - return -1; -#endif - if (!pipeWriter) { pipeWriter = new QWindowsPipeWriter(stdinChannel.pipe[1], q); pipeWriter->start(); @@ -832,36 +772,19 @@ void QProcessPrivate::_q_notified() bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid) { -#if defined(Q_OS_WINCE) - Q_UNUSED(workingDir); - QString args = qt_create_commandline(QString(), arguments); -#else QString args = qt_create_commandline(program, arguments); -#endif - bool success = false; - PROCESS_INFORMATION pinfo; -#if defined(Q_OS_WINCE) - QString fullPathProgram = program; - if (!QDir::isAbsolutePath(fullPathProgram)) - fullPathProgram.prepend(QDir::currentPath().append(QLatin1Char('/'))); - fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\')); - success = CreateProcess((wchar_t*)fullPathProgram.utf16(), - (wchar_t*)args.utf16(), - 0, 0, false, CREATE_NEW_CONSOLE, 0, 0, 0, &pinfo); -#else - STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, - (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, - (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - success = CreateProcess(0, (wchar_t*)args.utf16(), - 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, 0, - workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(), - &startupInfo, &pinfo); -#endif // Q_OS_WINCE + STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, + (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, + (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + success = CreateProcess(0, (wchar_t*)args.utf16(), + 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, 0, + workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(), + &startupInfo, &pinfo); if (success) { CloseHandle(pinfo.hThread); diff --git a/src/corelib/io/qprocess_wince.cpp b/src/corelib/io/qprocess_wince.cpp new file mode 100644 index 0000000000..16a34469e7 --- /dev/null +++ b/src/corelib/io/qprocess_wince.cpp @@ -0,0 +1,330 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qprocess.h" +#include "qprocess_p.h" + +#include <qdir.h> +#include <qfileinfo.h> +#include <qregexp.h> +#include <qtimer.h> +#include <qwineventnotifier.h> +#include <qdebug.h> + +#ifndef QT_NO_PROCESS + +QT_BEGIN_NAMESPACE + +//#define QPROCESS_DEBUG + +void QProcessPrivate::destroyPipe(Q_PIPE pipe[2]) +{ + Q_UNUSED(pipe); +} + +static QString qt_create_commandline(const QString &program, const QStringList &arguments) +{ + QString args; + if (!program.isEmpty()) { + QString programName = program; + if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' '))) + programName = QLatin1Char('\"') + programName + QLatin1Char('\"'); + programName.replace(QLatin1Char('/'), QLatin1Char('\\')); + + // add the prgram as the first arg ... it works better + args = programName + QLatin1Char(' '); + } + + for (int i=0; i<arguments.size(); ++i) { + QString tmp = arguments.at(i); + // Quotes are escaped and their preceding backslashes are doubled. + tmp.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); + if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) { + // The argument must not end with a \ since this would be interpreted + // as escaping the quote -- rather put the \ behind the quote: e.g. + // rather use "foo"\ than "foo\" + int i = tmp.length(); + while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\')) + --i; + tmp.insert(i, QLatin1Char('"')); + tmp.prepend(QLatin1Char('"')); + } + args += QLatin1Char(' ') + tmp; + } + return args; +} + +QProcessEnvironment QProcessEnvironment::systemEnvironment() +{ + QProcessEnvironment env; + return env; +} + +void QProcessPrivate::startProcess() +{ + Q_Q(QProcess); + + bool success = false; + + if (pid) { + CloseHandle(pid->hThread); + CloseHandle(pid->hProcess); + delete pid; + pid = 0; + } + pid = new PROCESS_INFORMATION; + memset(pid, 0, sizeof(PROCESS_INFORMATION)); + + q->setProcessState(QProcess::Starting); + + QString args = qt_create_commandline(QString(), arguments); + if (!nativeArguments.isEmpty()) { + if (!args.isEmpty()) + args += QLatin1Char(' '); + args += nativeArguments; + } + +#if defined QPROCESS_DEBUG + qDebug("Creating process"); + qDebug(" program : [%s]", program.toLatin1().constData()); + qDebug(" args : %s", args.toLatin1().constData()); + qDebug(" pass environment : %s", environment.isEmpty() ? "no" : "yes"); +#endif + + QString fullPathProgram = program; + if (!QDir::isAbsolutePath(fullPathProgram)) + fullPathProgram = QFileInfo(fullPathProgram).absoluteFilePath(); + fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\')); + success = CreateProcess((wchar_t*)fullPathProgram.utf16(), + (wchar_t*)args.utf16(), + 0, 0, false, 0, 0, 0, 0, pid); + + if (!success) { + cleanup(); + processError = QProcess::FailedToStart; + emit q->error(processError); + q->setProcessState(QProcess::NotRunning); + return; + } + + q->setProcessState(QProcess::Running); + // User can call kill()/terminate() from the stateChanged() slot + // so check before proceeding + if (!pid) + return; + + if (threadData->eventDispatcher) { + processFinishedNotifier = new QWinEventNotifier(pid->hProcess, q); + QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_processDied())); + processFinishedNotifier->setEnabled(true); + } + + // give the process a chance to start ... + Sleep(SLEEPMIN * 2); + _q_startupNotification(); +} + +bool QProcessPrivate::processStarted() +{ + return processState == QProcess::Running; +} + +qint64 QProcessPrivate::bytesAvailableFromStdout() const +{ + return 0; +} + +qint64 QProcessPrivate::bytesAvailableFromStderr() const +{ + return 0; +} + +qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen) +{ + return -1; +} + +qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen) +{ + return -1; +} + +static BOOL QT_WIN_CALLBACK qt_terminateApp(HWND hwnd, LPARAM procId) +{ + DWORD currentProcId = 0; + GetWindowThreadProcessId(hwnd, ¤tProcId); + if (currentProcId == (DWORD)procId) + PostMessage(hwnd, WM_CLOSE, 0, 0); + + return TRUE; +} + +void QProcessPrivate::terminateProcess() +{ + if (pid) { + EnumWindows(qt_terminateApp, (LPARAM)pid->dwProcessId); + PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0); + } +} + +void QProcessPrivate::killProcess() +{ + if (pid) + TerminateProcess(pid->hProcess, 0xf291); +} + +bool QProcessPrivate::waitForStarted(int) +{ + Q_Q(QProcess); + + if (processStarted()) + return true; + + if (processError == QProcess::FailedToStart) + return false; + + processError = QProcess::Timedout; + q->setErrorString(QProcess::tr("Process operation timed out")); + return false; +} + +bool QProcessPrivate::waitForReadyRead(int msecs) +{ + return false; +} + +bool QProcessPrivate::waitForBytesWritten(int msecs) +{ + return false; +} + +bool QProcessPrivate::waitForFinished(int msecs) +{ + Q_Q(QProcess); +#if defined QPROCESS_DEBUG + qDebug("QProcessPrivate::waitForFinished(%d)", msecs); +#endif + + QIncrementalSleepTimer timer(msecs); + + forever { + if (!pid) + return true; + + if (WaitForSingleObject(pid->hProcess, timer.nextSleepTime()) == WAIT_OBJECT_0) { + _q_processDied(); + return true; + } + + if (timer.hasTimedOut()) + break; + } + processError = QProcess::Timedout; + q->setErrorString(QProcess::tr("Process operation timed out")); + return false; +} + +void QProcessPrivate::findExitCode() +{ + DWORD theExitCode; + if (GetExitCodeProcess(pid->hProcess, &theExitCode)) { + exitCode = theExitCode; + //### for now we assume a crash if exit code is less than -1 or the magic number + crashed = (exitCode == 0xf291 || (int)exitCode < 0); + } +} + +void QProcessPrivate::flushPipeWriter() +{ +} + +qint64 QProcessPrivate::pipeWriterBytesToWrite() const +{ + return 0; +} + +qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen) +{ + Q_UNUSED(data); + Q_UNUSED(maxlen); + return -1; +} + +bool QProcessPrivate::waitForWrite(int msecs) +{ + Q_UNUSED(msecs); + return false; +} + +void QProcessPrivate::_q_notified() +{ +} + +bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid) +{ + Q_UNUSED(workingDir); + QString args = qt_create_commandline(QString(), arguments); + + bool success = false; + + PROCESS_INFORMATION pinfo; + + QString fullPathProgram = program; + if (!QDir::isAbsolutePath(fullPathProgram)) + fullPathProgram.prepend(QDir::currentPath().append(QLatin1Char('/'))); + fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\')); + success = CreateProcess((wchar_t*)fullPathProgram.utf16(), + (wchar_t*)args.utf16(), + 0, 0, false, CREATE_NEW_CONSOLE, 0, 0, 0, &pinfo); + + if (success) { + CloseHandle(pinfo.hThread); + CloseHandle(pinfo.hProcess); + if (pid) + *pid = pinfo.dwProcessId; + } + + return success; +} + +QT_END_NAMESPACE + +#endif // QT_NO_PROCESS diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 6ad15788b0..0ae3f9e647 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -1491,6 +1491,4 @@ bool QResourceFileEnginePrivate::unmap(uchar *ptr) return true; } -Q_CORE_EXPORT void qInitResourceIO() { } // ### Qt 5: remove - QT_END_NAMESPACE diff --git a/src/corelib/io/qresource.h b/src/corelib/io/qresource.h index 1edc7a4f13..452e141e41 100644 --- a/src/corelib/io/qresource.h +++ b/src/corelib/io/qresource.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qresource_iterator.cpp b/src/corelib/io/qresource_iterator.cpp index e19bad1e03..3317ef5fff 100644 --- a/src/corelib/io/qresource_iterator.cpp +++ b/src/corelib/io/qresource_iterator.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qresource_iterator_p.h b/src/corelib/io/qresource_iterator_p.h index 519f46199c..3603c64819 100644 --- a/src/corelib/io/qresource_iterator_p.h +++ b/src/corelib/io/qresource_iterator_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qresource_p.h b/src/corelib/io/qresource_p.h index 4beda142ed..f558319dc2 100644 --- a/src/corelib/io/qresource_p.h +++ b/src/corelib/io/qresource_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index 37bd8c460d..81dc5bb078 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qsettings.h b/src/corelib/io/qsettings.h index b144a9af4c..65aeb89523 100644 --- a/src/corelib/io/qsettings.h +++ b/src/corelib/io/qsettings.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp index 11e0c3c103..6bb815c561 100644 --- a/src/corelib/io/qsettings_mac.cpp +++ b/src/corelib/io/qsettings_mac.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h index 5d62c839a6..cf348122dc 100644 --- a/src/corelib/io/qsettings_p.h +++ b/src/corelib/io/qsettings_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp index bbc7dd1677..2cac379ec6 100644 --- a/src/corelib/io/qsettings_win.cpp +++ b/src/corelib/io/qsettings_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index 43ae5c07ab..5accb61cc5 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -83,6 +83,8 @@ QT_BEGIN_NAMESPACE returned for GenericDataLocation. \value CacheLocation Returns a directory location where user-specific non-essential (cached) data should be written. + \value GenericCacheLocation Returns a directory location where user-specific + non-essential (cached) data, shared across applications, should be written. \value GenericDataLocation Returns a directory location where persistent data shared across applications can be stored. \value RuntimeLocation Returns a directory location where runtime communication diff --git a/src/corelib/io/qstandardpaths.h b/src/corelib/io/qstandardpaths.h index d91da9de2f..bae7b3f7b5 100644 --- a/src/corelib/io/qstandardpaths.h +++ b/src/corelib/io/qstandardpaths.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -73,7 +73,8 @@ public: GenericDataLocation, RuntimeLocation, ConfigLocation, - DownloadLocation + DownloadLocation, + GenericCacheLocation }; static QString writableLocation(StandardLocation type); diff --git a/src/corelib/io/qstandardpaths_mac.cpp b/src/corelib/io/qstandardpaths_mac.cpp index 84fc81494c..f37c21ed39 100644 --- a/src/corelib/io/qstandardpaths_mac.cpp +++ b/src/corelib/io/qstandardpaths_mac.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -82,6 +82,7 @@ OSType translateLocation(QStandardPaths::StandardLocation type) case QStandardPaths::RuntimeLocation: case QStandardPaths::DataLocation: return kApplicationSupportFolderType; + case QStandardPaths::GenericCacheLocation: case QStandardPaths::CacheLocation: return kCachedDataFolderType; default: @@ -128,6 +129,7 @@ QString QStandardPaths::writableLocation(StandardLocation type) return QDir::tempPath(); case GenericDataLocation: case DataLocation: + case GenericCacheLocation: case CacheLocation: case RuntimeLocation: return macLocation(type, kUserDomain); @@ -140,7 +142,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type) { QStringList dirs; - if (type == GenericDataLocation || type == DataLocation || type == CacheLocation) { + if (type == GenericDataLocation || type == DataLocation || type == GenericCacheLocation || type == CacheLocation) { const QString path = macLocation(type, kOnAppropriateDisk); if (!path.isEmpty()) dirs.append(path); diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp index b1c5869f71..5aef52eaba 100644 --- a/src/corelib/io/qstandardpaths_unix.cpp +++ b/src/corelib/io/qstandardpaths_unix.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -62,15 +62,18 @@ QString QStandardPaths::writableLocation(StandardLocation type) case TempLocation: return QDir::tempPath(); case CacheLocation: + case GenericCacheLocation: { // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html QString xdgCacheHome = QFile::decodeName(qgetenv("XDG_CACHE_HOME")); if (xdgCacheHome.isEmpty()) xdgCacheHome = QDir::homePath() + QLatin1String("/.cache"); - if (!QCoreApplication::organizationName().isEmpty()) - xdgCacheHome += QLatin1Char('/') + QCoreApplication::organizationName(); - if (!QCoreApplication::applicationName().isEmpty()) - xdgCacheHome += QLatin1Char('/') + QCoreApplication::applicationName(); + if (type == QStandardPaths::CacheLocation) { + if (!QCoreApplication::organizationName().isEmpty()) + xdgCacheHome += QLatin1Char('/') + QCoreApplication::organizationName(); + if (!QCoreApplication::applicationName().isEmpty()) + xdgCacheHome += QLatin1Char('/') + QCoreApplication::applicationName(); + } return xdgCacheHome; } case DataLocation: diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp index e9093649f3..e3f86b7134 100644 --- a/src/corelib/io/qstandardpaths_win.cpp +++ b/src/corelib/io/qstandardpaths_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -160,6 +160,9 @@ QString QStandardPaths::writableLocation(StandardLocation type) // cache directory located in their AppData directory return writableLocation(DataLocation) + QLatin1String("\\cache"); + case GenericCacheLocation: + return writableLocation(GenericDataLocation) + QLatin1String("\\cache"); + case RuntimeLocation: case HomeLocation: result = QDir::homePath(); diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp index 78ec1774eb..15d3258a9a 100644 --- a/src/corelib/io/qtemporarydir.cpp +++ b/src/corelib/io/qtemporarydir.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h index da0d1214c4..22c0a271e4 100644 --- a/src/corelib/io/qtemporarydir.h +++ b/src/corelib/io/qtemporarydir.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 677be45f65..eb645fabe8 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qtemporaryfile.h b/src/corelib/io/qtemporaryfile.h index 282b897813..20956d2cf0 100644 --- a/src/corelib/io/qtemporaryfile.h +++ b/src/corelib/io/qtemporaryfile.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 177f73def3..8c7f57fddf 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h index db038855a8..0531d4017d 100644 --- a/src/corelib/io/qtextstream.h +++ b/src/corelib/io/qtextstream.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qtldurl.cpp b/src/corelib/io/qtldurl.cpp index 7d06ca4b17..2c725f17fd 100644 --- a/src/corelib/io/qtldurl.cpp +++ b/src/corelib/io/qtldurl.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qtldurl_p.h b/src/corelib/io/qtldurl_p.h index 77c0a15823..0a94f3015b 100644 --- a/src/corelib/io/qtldurl_p.h +++ b/src/corelib/io/qtldurl_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index c921a89b30..53b4df4729 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index e62cd0a85b..75a88e8048 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp new file mode 100644 index 0000000000..8da786ebd9 --- /dev/null +++ b/src/corelib/io/qwindowspipereader.cpp @@ -0,0 +1,315 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowspipereader_p.h" +#include <qdebug.h> +#include <qelapsedtimer.h> +#include <qeventloop.h> +#include <qtimer.h> +#include <qwineventnotifier.h> + +QT_BEGIN_NAMESPACE + +QWindowsPipeReader::QWindowsPipeReader(QObject *parent) + : QObject(parent), + handle(INVALID_HANDLE_VALUE), + readBufferMaxSize(0), + actualReadBufferSize(0), + emitReadyReadTimer(new QTimer(this)), + pipeBroken(false) +{ + emitReadyReadTimer->setSingleShot(true); + connect(emitReadyReadTimer, SIGNAL(timeout()), SIGNAL(readyRead())); + + ZeroMemory(&overlapped, sizeof(overlapped)); + overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + dataReadNotifier = new QWinEventNotifier(overlapped.hEvent, this); + connect(dataReadNotifier, SIGNAL(activated(HANDLE)), SLOT(readEventSignalled())); +} + +QWindowsPipeReader::~QWindowsPipeReader() +{ + CloseHandle(overlapped.hEvent); +} + +/*! + Sets the handle to read from. The handle must be valid. + */ +void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd) +{ + readBuffer.clear(); + actualReadBufferSize = 0; + handle = hPipeReadEnd; + pipeBroken = false; + dataReadNotifier->setEnabled(true); +} + +/*! + Stops the asynchronous read sequence. + This function assumes that the file already has been closed. + It does not cancel any I/O operation. + */ +void QWindowsPipeReader::stop() +{ + dataReadNotifier->setEnabled(false); + readSequenceStarted = false; + handle = INVALID_HANDLE_VALUE; + ResetEvent(overlapped.hEvent); +} + +/*! + Returns the number of bytes we've read so far. + */ +qint64 QWindowsPipeReader::bytesAvailable() const +{ + return actualReadBufferSize; +} + +/*! + Stops the asynchronous read sequence. + */ +qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) +{ + if (pipeBroken && actualReadBufferSize == 0) + return -1; // signal EOF + + qint64 readSoFar; + // If startAsyncRead() has read data, copy it to its destination. + if (maxlen == 1 && actualReadBufferSize > 0) { + *data = readBuffer.getChar(); + actualReadBufferSize--; + readSoFar = 1; + } else { + qint64 bytesToRead = qMin(qint64(actualReadBufferSize), maxlen); + readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readBuffer.readPointer(); + int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, + qint64(readBuffer.nextDataBlockSize())); + memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + readBuffer.free(bytesToReadFromThisBlock); + actualReadBufferSize -= bytesToReadFromThisBlock; + } + } + + if (!pipeBroken) { + if (!actualReadBufferSize) + emitReadyReadTimer->stop(); + if (!readSequenceStarted) + startAsyncRead(); + } + + return readSoFar; +} + +bool QWindowsPipeReader::canReadLine() const +{ + return readBuffer.indexOf('\n', actualReadBufferSize) >= 0; +} + +/*! + \internal + Will be called whenever the read operation completes. + Returns true, if readyRead() has been emitted. + */ +bool QWindowsPipeReader::readEventSignalled() +{ + if (!completeAsyncRead()) { + pipeBroken = true; + emit pipeClosed(); + return false; + } + startAsyncRead(); + emitReadyReadTimer->stop(); + emit readyRead(); + return true; +} + +/*! + \internal + Reads data from the socket into the readbuffer + */ +void QWindowsPipeReader::startAsyncRead() +{ + do { + DWORD bytesToRead = checkPipeState(); + if (pipeBroken) + return; + + if (bytesToRead == 0) { + // There are no bytes in the pipe but we need to + // start the overlapped read with some buffer size. + bytesToRead = initialReadBufferSize; + } + + if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { + bytesToRead = readBufferMaxSize - readBuffer.size(); + if (bytesToRead == 0) { + // Buffer is full. User must read data from the buffer + // before we can read more from the pipe. + return; + } + } + + char *ptr = readBuffer.reserve(bytesToRead); + + readSequenceStarted = true; + if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) { + completeAsyncRead(); + } else { + switch (GetLastError()) { + case ERROR_IO_PENDING: + // This is not an error. We're getting notified, when data arrives. + return; + case ERROR_MORE_DATA: + // This is not an error. The synchronous read succeeded. + // We're connected to a message mode pipe and the message + // didn't fit into the pipe's system buffer. + completeAsyncRead(); + break; + case ERROR_PIPE_NOT_CONNECTED: + { + // It may happen, that the other side closes the connection directly + // after writing data. Then we must set the appropriate socket state. + pipeBroken = true; + emit pipeClosed(); + return; + } + default: + emit winError(GetLastError(), QLatin1String("QWindowsPipeReader::startAsyncRead")); + return; + } + } + } while (!readSequenceStarted); +} + +/*! + \internal + Sets the correct size of the read buffer after a read operation. + Returns false, if an error occurred or the connection dropped. + */ +bool QWindowsPipeReader::completeAsyncRead() +{ + ResetEvent(overlapped.hEvent); + readSequenceStarted = false; + + DWORD bytesRead; + if (!GetOverlappedResult(handle, &overlapped, &bytesRead, TRUE)) { + switch (GetLastError()) { + case ERROR_MORE_DATA: + // This is not an error. We're connected to a message mode + // pipe and the message didn't fit into the pipe's system + // buffer. We will read the remaining data in the next call. + break; + case ERROR_BROKEN_PIPE: + case ERROR_PIPE_NOT_CONNECTED: + return false; + default: + emit winError(GetLastError(), QLatin1String("QWindowsPipeReader::completeAsyncRead")); + return false; + } + } + + actualReadBufferSize += bytesRead; + readBuffer.truncate(actualReadBufferSize); + if (!emitReadyReadTimer->isActive()) + emitReadyReadTimer->start(); + return true; +} + +/*! + \internal + Returns the number of available bytes in the pipe. + Sets QWindowsPipeReader::pipeBroken to true if the connection is broken. + */ +DWORD QWindowsPipeReader::checkPipeState() +{ + DWORD bytes; + if (PeekNamedPipe(handle, NULL, 0, NULL, &bytes, NULL)) { + return bytes; + } else { + if (!pipeBroken) { + pipeBroken = true; + emit pipeClosed(); + } + } + return 0; +} + +/*! + Waits for the completion of the asynchronous read operation. + Returns true, if we've emitted the readyRead signal. + */ +bool QWindowsPipeReader::waitForReadyRead(int msecs) +{ + Q_ASSERT(readSequenceStarted); + DWORD result = WaitForSingleObject(overlapped.hEvent, msecs == -1 ? INFINITE : msecs); + switch (result) { + case WAIT_OBJECT_0: + return readEventSignalled(); + case WAIT_TIMEOUT: + return false; + } + + qWarning("QWindowsPipeReader::waitForReadyRead WaitForSingleObject failed with error code %d.", int(GetLastError())); + return false; +} + +/*! + Waits until the pipe is closed. + */ +bool QWindowsPipeReader::waitForPipeClosed(int msecs) +{ + const int sleepTime = 10; + QElapsedTimer stopWatch; + stopWatch.start(); + forever { + checkPipeState(); + if (pipeBroken) + return true; + if (stopWatch.hasExpired(msecs - sleepTime)) + return false; + Sleep(sleepTime); + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemwatcher_symbian_p.h b/src/corelib/io/qwindowspipereader_p.h index 0b317a062f..e78d6b29ad 100644 --- a/src/corelib/io/qfilesystemwatcher_symbian_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QFILESYSTEMWATCHER_SYMBIAN_P_H -#define QFILESYSTEMWATCHER_SYMBIAN_P_H +#ifndef QWINDOWSPIPEREADER_P_H +#define QWINDOWSPIPEREADER_P_H // // W A R N I N G @@ -53,78 +53,70 @@ // We mean it. // -#include "qfilesystemwatcher_p.h" +#include <qbytearray.h> +#include <qobject.h> +#include <qtimer.h> +#include <qt_windows.h> -#ifndef QT_NO_FILESYSTEMWATCHER +#include <private/qringbuffer_p.h> -#include "qhash.h" -#include "qmutex.h" -#include "qwaitcondition.h" - -#include <e32base.h> -#include <f32file.h> +QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class QSymbianFileSystemWatcherEngine; - -class QNotifyChangeEvent : public CActive -{ -public: - QNotifyChangeEvent(RFs &fsSession, const TDesC &file, QSymbianFileSystemWatcherEngine *engine, - bool aIsDir, TInt aPriority = EPriorityStandard); - ~QNotifyChangeEvent(); - - bool isDir; +QT_MODULE(Core) -private: - void RunL(); - void DoCancel(); - - RFs &fsSession; - TPath watchedPath; - QSymbianFileSystemWatcherEngine *engine; - - int failureCount; -}; +class QWinEventNotifier; -class QSymbianFileSystemWatcherEngine : public QFileSystemWatcherEngine +class Q_CORE_EXPORT QWindowsPipeReader : public QObject { Q_OBJECT - public: - QSymbianFileSystemWatcherEngine(); - ~QSymbianFileSystemWatcherEngine(); - - QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); - QStringList removePaths(const QStringList &paths, QStringList *files, - QStringList *directories); + explicit QWindowsPipeReader(QObject *parent = 0); + ~QWindowsPipeReader(); + void setHandle(HANDLE hPipeReadEnd); void stop(); -protected: - void run(); + void setMaxReadBufferSize(qint64 size) { readBufferMaxSize = size; } + qint64 maxReadBufferSize() const { return readBufferMaxSize; } -public Q_SLOTS: - void addNativeListener(const QString &directoryPath); - void removeNativeListener(); + bool isPipeClosed() const { return pipeBroken; } + qint64 bytesAvailable() const; + qint64 read(char *data, qint64 maxlen); + bool canReadLine() const; + bool waitForReadyRead(int msecs); + bool waitForPipeClosed(int msecs); -private: - friend class QNotifyChangeEvent; - void emitPathChanged(QNotifyChangeEvent *e); + void startAsyncRead(); + bool completeAsyncRead(); - void startWatcher(); +Q_SIGNALS: + void winError(ulong, const QString &); + void readyRead(); + void pipeClosed(); - QHash<QNotifyChangeEvent*, QString> activeObjectToPath; - QMutex mutex; - QWaitCondition syncCondition; - bool watcherStarted; - QNotifyChangeEvent *currentAddEvent; - QNotifyChangeEvent *currentRemoveEvent; -}; +private Q_SLOTS: + bool readEventSignalled(); -#endif // QT_NO_FILESYSTEMWATCHER +private: + DWORD checkPipeState(); + +private: + HANDLE handle; + OVERLAPPED overlapped; + QWinEventNotifier *dataReadNotifier; + qint64 readBufferMaxSize; + QRingBuffer readBuffer; + int actualReadBufferSize; + bool readSequenceStarted; + QTimer *emitReadyReadTimer; + bool pipeBroken; + static const qint64 initialReadBufferSize = 4096; +}; QT_END_NAMESPACE -#endif // QFILESYSTEMWATCHER_WIN_P_H +QT_END_HEADER + +#endif // QWINDOWSPIPEREADER_P_H diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp index cb802f1d91..a1765b4178 100644 --- a/src/corelib/io/qwindowspipewriter.cpp +++ b/src/corelib/io/qwindowspipewriter.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/corelib/io/qwindowspipewriter_p.h b/src/corelib/io/qwindowspipewriter_p.h index dfcb77e17c..44a1d04b4e 100644 --- a/src/corelib/io/qwindowspipewriter_p.h +++ b/src/corelib/io/qwindowspipewriter_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** |