diff options
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/qabstractfileengine.cpp | 13 | ||||
-rw-r--r-- | src/corelib/io/qabstractfileengine_p.h | 1 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.cpp | 1 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.h | 5 | ||||
-rw-r--r-- | src/corelib/io/qdebug.cpp | 15 | ||||
-rw-r--r-- | src/corelib/io/qdebug.h | 3 | ||||
-rw-r--r-- | src/corelib/io/qfile.cpp | 45 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemengine_unix.cpp | 18 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemengine_win.cpp | 52 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine.cpp | 13 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_p.h | 1 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_unix.cpp | 113 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_win.cpp | 9 | ||||
-rw-r--r-- | src/corelib/io/qprocess.cpp | 71 | ||||
-rw-r--r-- | src/corelib/io/qprocess.h | 1 | ||||
-rw-r--r-- | src/corelib/io/qprocess_p.h | 5 | ||||
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 105 | ||||
-rw-r--r-- | src/corelib/io/qprocess_win.cpp | 41 | ||||
-rw-r--r-- | src/corelib/io/qresource.cpp | 50 | ||||
-rw-r--r-- | src/corelib/io/qsettings.cpp | 2 | ||||
-rw-r--r-- | src/corelib/io/qsettings_p.h | 2 | ||||
-rw-r--r-- | src/corelib/io/qtemporaryfile_p.h | 2 | ||||
-rw-r--r-- | src/corelib/io/qtldurl.cpp | 42 |
23 files changed, 320 insertions, 290 deletions
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 9606ec68e9..5f1f7e381e 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -832,6 +832,19 @@ bool QAbstractFileEngine::unmap(uchar *address) } /*! + \since 5.10 + + Copies the contents from the file specified by \a sourceHandle to this file + by cloning it. + Returns \c true on success; otherwise, \c false is returned. + */ +bool QAbstractFileEngine::clone(int sourceHandle) +{ + Q_UNUSED(sourceHandle); + return false; +} + +/*! \since 4.3 \class QAbstractFileEngineIterator \inmodule QtCore diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h index 48b3dec324..dbf0d77b15 100644 --- a/src/corelib/io/qabstractfileengine_p.h +++ b/src/corelib/io/qabstractfileengine_p.h @@ -147,6 +147,7 @@ public: virtual QDateTime fileTime(FileTime time) const; virtual void setFileName(const QString &file); virtual int handle() const; + virtual bool clone(int sourceHandle); bool atEnd() const; uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags); bool unmap(uchar *ptr); diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 2369fe4726..58e2500057 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -562,6 +562,7 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_5_7 Same as Qt_5_6 \value Qt_5_8 Same as Qt_5_6 \value Qt_5_9 Same as Qt_5_6 + \value Qt_5_10 Same as Qt_5_6 \omitvalue Qt_DefaultCompiledVersion \sa setVersion(), version() diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index db1bbfbd63..993a20fcd3 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -96,10 +96,11 @@ public: Qt_5_7 = Qt_5_6, Qt_5_8 = Qt_5_7, Qt_5_9 = Qt_5_8, -#if QT_VERSION >= 0x050a00 + Qt_5_10 = Qt_5_9, +#if QT_VERSION >= 0x050b00 #error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion #endif - Qt_DefaultCompiledVersion = Qt_5_9 + Qt_DefaultCompiledVersion = Qt_5_10 }; enum ByteOrder { diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index be33ec2d23..341400fd93 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -648,6 +648,21 @@ QDebug &QDebug::resetFormat() */ /*! + \since 5.10 + \fn QDebug &QDebug::operator<<(QStringView s) + + Writes the string view, \a s, to the stream and returns a reference to the + stream. Normally, QDebug prints the string inside quotes and transforms + non-printable characters to their Unicode values (\\u1234). + + To print non-printable characters without transformation, enable the + noquote() functionality. Note that some QDebug backends might not be 8-bit + clean. + + See the QString overload for examples. +*/ + +/*! \fn QDebug &QDebug::operator<<(QLatin1String s) Writes the string, \a s, to the stream and returns a reference to the diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 61059dd694..d5f32a6efd 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -151,8 +151,11 @@ public: inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); } +#if QT_STRINGVIEW_LEVEL < 2 inline QDebug &operator<<(const QString & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); } inline QDebug &operator<<(const QStringRef & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); } +#endif + inline QDebug &operator<<(QStringView s) { putString(s.data(), size_t(s.size())); return maybeSpace(); } inline QDebug &operator<<(QLatin1String t) { putByteArray(t.latin1(), t.size(), ContainsLatin1); return maybeSpace(); } inline QDebug &operator<<(const QByteArray & t) { putByteArray(t.constData(), t.size(), ContainsBinary); return maybeSpace(); } inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); } diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 41fae69bb2..c19cb92715 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -42,6 +42,7 @@ #include "qfile.h" #include "qfsfileengine_p.h" #include "qtemporaryfile.h" +#include "qtemporaryfile_p.h" #include "qlist.h" #include "qfileinfo.h" #include "private/qiodevice_p.h" @@ -790,25 +791,27 @@ QFile::copy(const QString &newName) close(); d->setError(QFile::CopyError, tr("Cannot open for output")); } else { - char block[4096]; - qint64 totalRead = 0; - while(!atEnd()) { - qint64 in = read(block, sizeof(block)); - if (in <= 0) - break; - totalRead += in; - if(in != out.write(block, in)) { - close(); - d->setError(QFile::CopyError, tr("Failure to write block")); - error = true; - break; + if (!out.d_func()->engine()->clone(d->engine()->handle())) { + char block[4096]; + qint64 totalRead = 0; + while (!atEnd()) { + qint64 in = read(block, sizeof(block)); + if (in <= 0) + break; + totalRead += in; + if (in != out.write(block, in)) { + close(); + d->setError(QFile::CopyError, tr("Failure to write block")); + error = true; + break; + } } - } - if (totalRead != size()) { - // Unable to read from the source. The error string is - // already set from read(). - error = true; + if (totalRead != size()) { + // Unable to read from the source. The error string is + // already set from read(). + error = true; + } } if (!error && !out.rename(newName)) { error = true; @@ -953,7 +956,9 @@ bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags) qWarning("QFile::open: File access not specified"); return false; } - if (d->openExternalFile(mode, fh, handleFlags)) { + + // QIODevice provides the buffering, so request unbuffered file engines + if (d->openExternalFile(mode | Unbuffered, fh, handleFlags)) { QIODevice::open(mode); if (!(mode & Append) && !isSequential()) { qint64 pos = (qint64)QT_FTELL(fh); @@ -1009,7 +1014,9 @@ bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags) qWarning("QFile::open: File access not specified"); return false; } - if (d->openExternalFile(mode, fd, handleFlags)) { + + // QIODevice provides the buffering, so request unbuffered file engines + if (d->openExternalFile(mode | Unbuffered, fd, handleFlags)) { QIODevice::open(mode); if (!(mode & Append) && !isSequential()) { qint64 pos = (qint64)QT_LSEEK(fd, QT_OFF_T(0), SEEK_CUR); diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 3cb412e47c..b8dca93f61 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -42,6 +42,7 @@ #include "qfilesystemengine_p.h" #include "qfile.h" +#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qvarlengtharray.h> #include <stdlib.h> // for realpath() @@ -66,6 +67,9 @@ #endif #if defined(Q_OS_DARWIN) +# if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(101200, 100000, 100000, 30000) +# include <sys/clonefile.h> +# endif // We cannot include <Foundation/Foundation.h> (it's an Objective-C header), but // we need these declarations: Q_FORWARD_DECLARE_OBJC_CLASS(NSString); @@ -659,8 +663,22 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy //static bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) { +#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(101200, 100000, 100000, 30000) + const auto current = QOperatingSystemVersion::current(); + if (current >= QOperatingSystemVersion::MacOSSierra || + current >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 10) || + current >= QOperatingSystemVersion(QOperatingSystemVersion::TvOS, 10) || + current >= QOperatingSystemVersion(QOperatingSystemVersion::WatchOS, 3)) { + if (::clonefile(source.nativeFilePath().constData(), + target.nativeFilePath().constData(), 0) == 0) + return true; + error = QSystemError(errno, QSystemError::StandardLibraryError); + return false; + } +#else Q_UNUSED(source); Q_UNUSED(target); +#endif error = QSystemError(ENOSYS, QSystemError::StandardLibraryError); //Function not implemented return false; } diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index b1e218de9c..d95a6de777 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -48,7 +48,6 @@ #include "qfile.h" #include "qdir.h" -#include "private/qmutexpool_p.h" #include "qvarlengtharray.h" #include "qdatetime.h" #include "qt_windows.h" @@ -179,6 +178,7 @@ static TRUSTEE_W worldTrusteeW; static PSID currentUserSID = 0; static PSID worldSID = 0; +namespace { /* Deletes the allocated SIDs during global static cleanup */ @@ -202,25 +202,10 @@ SidCleanup::~SidCleanup() Q_GLOBAL_STATIC(SidCleanup, initSidCleanup) -static void resolveLibs() +struct LibResolver { - static bool triedResolve = false; - if (!triedResolve) { - // need to resolve the security info functions - - // protect initialization -#ifndef QT_NO_THREAD - QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); - // check triedResolve again, since another thread may have already - // done the initialization - if (triedResolve) { - // another thread did initialize the security function pointers, - // so we shouldn't do it again. - return; - } -#endif - - triedResolve = true; + LibResolver() + { HINSTANCE advapiHnd = QSystemLibrary::load(L"advapi32"); if (advapiHnd) { ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW"); @@ -267,9 +252,13 @@ static void resolveLibs() if (userenvHnd) ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW"); } -} +}; +Q_GLOBAL_STATIC(LibResolver, resolveLibs) + +} // anonymous namespace #endif // QT_CONFIG(fslibs) +QT_BEGIN_INCLUDE_NAMESPACE typedef DWORD (WINAPI *PtrNetShareEnum)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD); static PtrNetShareEnum ptrNetShareEnum = 0; typedef DWORD (WINAPI *PtrNetApiBufferFree)(LPVOID); @@ -279,19 +268,13 @@ typedef struct _SHARE_INFO_1 { DWORD shi1_type; LPWSTR shi1_remark; } SHARE_INFO_1; +QT_END_INCLUDE_NAMESPACE - -static bool resolveUNCLibs() +namespace { +struct UNCLibResolver { - static bool triedResolve = false; - if (!triedResolve) { -#ifndef QT_NO_THREAD - QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); - if (triedResolve) { - return ptrNetShareEnum && ptrNetApiBufferFree; - } -#endif - triedResolve = true; + UNCLibResolver() + { #if !defined(Q_OS_WINRT) HINSTANCE hLib = QSystemLibrary::load(L"Netapi32"); if (hLib) { @@ -301,6 +284,13 @@ static bool resolveUNCLibs() } #endif // !Q_OS_WINRT } +}; +Q_GLOBAL_STATIC(UNCLibResolver, uncLibResolver) +} // anonymous namespace + +static bool resolveUNCLibs() +{ + uncLibResolver(); return ptrNetShareEnum && ptrNetApiBufferFree; } diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 0b9cd0557f..e5f7e5b418 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -195,6 +195,9 @@ void QFSFileEngine::setFileName(const QString &file) */ bool QFSFileEngine::open(QIODevice::OpenMode openMode) { + Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open", + "QFSFileEngine no longer supports buffered mode; upper layer must buffer"); + Q_D(QFSFileEngine); if (d->fileEntry.isEmpty()) { qWarning("QFSFileEngine::open: No file name specified"); @@ -230,6 +233,9 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh) bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHandleFlags handleFlags) { + Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open", + "QFSFileEngine no longer supports buffered mode; upper layer must buffer"); + Q_D(QFSFileEngine); // Append implies WriteOnly. @@ -255,6 +261,9 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHand */ bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh) { + Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open", + "QFSFileEngine no longer supports buffered mode; upper layer must buffer"); + Q_Q(QFSFileEngine); this->fh = fh; fd = -1; @@ -860,9 +869,9 @@ bool QFSFileEngine::supportsExtension(Extension extension) const /*! \fn bool QFSFileEngine::copy(const QString ©Name) - For windows, copy the file to file \a copyName. + For Windows or Apple platforms, copy the file to file \a copyName. - Not implemented for Unix. + Not implemented for other Unix platforms. */ /*! \fn QString QFSFileEngine::currentPath(const QString &fileName) diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index 593ecc2687..742cebad87 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -108,6 +108,7 @@ public: qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; qint64 readLine(char *data, qint64 maxlen) Q_DECL_OVERRIDE; qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE; + bool clone(int sourceHandle) override; bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) Q_DECL_OVERRIDE; bool supportsExtension(Extension extension) const Q_DECL_OVERRIDE; diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index e152b035e2..51938d6967 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -65,46 +65,6 @@ QT_BEGIN_NAMESPACE /*! \internal - Returns the stdlib open string corresponding to a QIODevice::OpenMode. -*/ -static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QFileSystemEntry &fileEntry, - QFileSystemMetaData &metaData) -{ - QByteArray mode; - if ((flags & QIODevice::ReadOnly) && !(flags & QIODevice::Truncate)) { - mode = "rb"; - if (flags & QIODevice::WriteOnly) { - metaData.clearFlags(QFileSystemMetaData::FileType); - if (!fileEntry.isEmpty() - && QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::FileType) - && metaData.isFile()) { - mode += '+'; - } else { - mode = "wb+"; - } - } - } else if (flags & QIODevice::WriteOnly) { - mode = "wb"; - if (flags & QIODevice::ReadOnly) - mode += '+'; - } - if (flags & QIODevice::Append) { - mode = "ab"; - if (flags & QIODevice::ReadOnly) - mode += '+'; - } - -#if defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0207 - // must be glibc >= 2.7 - mode += 'e'; -#endif - - return mode; -} - -/*! - \internal - Returns the stdio open flags corresponding to a QIODevice::OpenMode. */ static inline int openModeToOpenFlags(QIODevice::OpenMode mode) @@ -130,17 +90,6 @@ static inline int openModeToOpenFlags(QIODevice::OpenMode mode) return oflags; } -/*! - \internal - - Sets the file descriptor to close on exec. That is, the file - descriptor is not inherited by child processes. -*/ -static inline bool setCloseOnExec(int fd) -{ - return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1; -} - static inline QString msgOpenDirectory() { const char message[] = QT_TRANSLATE_NOOP("QIODevice", "file to open is a directory"); @@ -158,6 +107,8 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) { Q_Q(QFSFileEngine); + Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open", + "QFSFileEngine no longer supports buffered mode; upper layer must buffer"); if (openMode & QIODevice::Unbuffered) { int flags = openModeToOpenFlags(openMode); @@ -199,49 +150,6 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) } fh = 0; - } else { - QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry, metaData); - - // Try to open the file in buffered mode. - do { - fh = QT_FOPEN(fileEntry.nativeFilePath().constData(), fopenMode.constData()); - } while (!fh && errno == EINTR); - - // On failure, return and report the error. - if (!fh) { - q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, - qt_error_string(int(errno))); - return false; - } - - if (!(openMode & QIODevice::WriteOnly)) { - // we don't need this check if we tried to open for writing because then - // we had received EISDIR anyway. - if (QFileSystemEngine::fillMetaData(QT_FILENO(fh), metaData) - && metaData.isDirectory()) { - q->setError(QFile::OpenError, msgOpenDirectory()); - fclose(fh); - return false; - } - } - - setCloseOnExec(fileno(fh)); // ignore failure - - // Seek to the end when in Append mode. - if (openMode & QIODevice::Append) { - int ret; - do { - ret = QT_FSEEK(fh, 0, SEEK_END); - } while (ret == -1 && errno == EINTR); - - if (ret == -1) { - q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, - qt_error_string(int(errno))); - return false; - } - } - - fd = -1; } closeFileHandle = true; @@ -793,6 +701,23 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) #endif } +/*! + \reimp +*/ +bool QFSFileEngine::clone(int sourceHandle) +{ +#if defined(Q_OS_LINUX) + Q_D(QFSFileEngine); +# if !defined FICLONE +# define FICLONE _IOW (0x94, 9, int) +# endif + return ::ioctl(d->fd, FICLONE, sourceHandle) == 0; +#else + Q_UNUSED(sourceHandle); + return false; +#endif +} + QT_END_NAMESPACE #endif // QT_NO_FSFILEENGINE diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 7d16e59195..4a477b8429 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -998,4 +998,13 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) return true; } +/*! + \reimp +*/ +bool QFSFileEngine::clone(int sourceHandle) +{ + Q_UNUSED(sourceHandle); + return false; +} + QT_END_NAMESPACE diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index c0ec35ff32..a3343423db 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -2112,6 +2112,46 @@ void QProcess::start(OpenMode mode) } /*! + \since 5.10 + + Starts the program set by setProgram() with arguments set by setArguments() + in a new process, and detaches from it. Returns \c true on success; + otherwise returns \c false. If the calling process exits, the + detached process will continue to run unaffected. + + \b{Unix:} The started process will run in its own session and act + like a daemon. + + The process will be started in the directory set by setWorkingDirectory(). + If workingDirectory() is empty, the working directory is inherited + from the calling process. + + \note On QNX, this may cause all application threads to + temporarily freeze. + + If the function is successful then *\a pid is set to the process + identifier of the started process. + + \sa start() + \sa startDetached(const QString &program, const QStringList &arguments, + const QString &workingDirectory, qint64 *pid) + \sa startDetached(const QString &command) +*/ +bool QProcess::startDetached(qint64 *pid) +{ + Q_D(QProcess); + if (d->processState != NotRunning) { + qWarning("QProcess::startDetached: Process is already running"); + return false; + } + if (d->program.isEmpty()) { + d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined")); + return false; + } + return d->startDetached(pid); +} + +/*! Starts the program set by setProgram() with arguments set by setArguments(). The OpenMode is set to \a mode. @@ -2445,6 +2485,8 @@ int QProcess::execute(const QString &command) } /*! + \overload startDetached() + Starts the program \a program with the arguments \a arguments in a new process, and detaches from it. Returns \c true on success; otherwise returns \c false. If the calling process exits, the @@ -2452,16 +2494,10 @@ int QProcess::execute(const QString &command) Argument handling is identical to the respective start() overload. - \b{Unix:} The started process will run in its own session and act - like a daemon. - The process will be started in the directory \a workingDirectory. If \a workingDirectory is empty, the working directory is inherited from the calling process. - \note On QNX, this may cause all application threads to - temporarily freeze. - If the function is successful then *\a pid is set to the process identifier of the started process. @@ -2472,10 +2508,11 @@ bool QProcess::startDetached(const QString &program, const QString &workingDirectory, qint64 *pid) { - return QProcessPrivate::startDetached(program, - arguments, - workingDirectory, - pid); + QProcess process; + process.setProgram(program); + process.setArguments(arguments); + process.setWorkingDirectory(workingDirectory); + return process.startDetached(pid); } /*! @@ -2484,11 +2521,14 @@ bool QProcess::startDetached(const QString &program, bool QProcess::startDetached(const QString &program, const QStringList &arguments) { - return QProcessPrivate::startDetached(program, arguments); + QProcess process; + process.setProgram(program); + process.setArguments(arguments); + return process.startDetached(); } /*! - \overload + \overload startDetached() Starts the command \a command in a new process, and detaches from it. Returns \c true on success; otherwise returns \c false. @@ -2506,9 +2546,10 @@ bool QProcess::startDetached(const QString &command) if (args.isEmpty()) return false; - const QString prog = args.takeFirst(); - - return QProcessPrivate::startDetached(prog, args); + QProcess process; + process.setProgram(args.takeFirst()); + process.setArguments(args); + return process.startDetached(); } QT_BEGIN_INCLUDE_NAMESPACE diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 19157bdd02..c8aef2f0b1 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -163,6 +163,7 @@ public: void start(const QString &command, OpenMode mode = ReadWrite); #endif void start(OpenMode mode = ReadWrite); + bool startDetached(qint64 *pid = nullptr); bool open(OpenMode mode = ReadWrite) Q_DECL_OVERRIDE; QString program() const; diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 6e0630eb66..80ac631290 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -353,7 +353,7 @@ public: void start(QIODevice::OpenMode mode); void startProcess(); #if defined(Q_OS_UNIX) - void execChild(const char *workingDirectory, char **path, char **argv, char **envp); + void execChild(const char *workingDirectory, char **argv, char **envp); #endif bool processStarted(QString *errorMessage = Q_NULLPTR); void terminateProcess(); @@ -368,8 +368,7 @@ public: qint64 pipeWriterBytesToWrite() const; #endif - static bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(), - qint64 *pid = 0); + bool startDetached(qint64 *pPid); int exitCode; QProcess::ExitStatus exitStatus; diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 795229419c..e72773d7a4 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -87,6 +87,7 @@ QT_END_NAMESPACE #include "qprocess.h" #include "qprocess_p.h" +#include "qstandardpaths.h" #include "private/qcore_unix_p.h" #ifdef Q_OS_MAC @@ -420,8 +421,16 @@ void QProcessPrivate::startProcess() #endif // Add the program name to the argument list. - char *dupProgramName = ::strdup(encodedProgramName.constData()); - argv[0] = dupProgramName; + argv[0] = nullptr; + if (!program.contains(QLatin1Char('/'))) { + const QString &exeFilePath = QStandardPaths::findExecutable(program); + if (!exeFilePath.isEmpty()) { + const QByteArray &tmp = QFile::encodeName(exeFilePath); + argv[0] = ::strdup(tmp.constData()); + } + } + if (!argv[0]) + argv[0] = ::strdup(encodedProgramName.constData()); // Add every argument to the list for (int i = 0; i < arguments.count(); ++i) @@ -443,29 +452,6 @@ void QProcessPrivate::startProcess() workingDirPtr = encodedWorkingDirectory.constData(); } - // If the program does not specify a path, generate a list of possible - // locations for the binary using the PATH environment variable. - char **path = 0; - int pathc = 0; - if (!program.contains(QLatin1Char('/'))) { - const QString pathEnv = QString::fromLocal8Bit(qgetenv("PATH")); - if (!pathEnv.isEmpty()) { - QStringList pathEntries = pathEnv.split(QLatin1Char(':'), QString::SkipEmptyParts); - if (!pathEntries.isEmpty()) { - pathc = pathEntries.size(); - path = new char *[pathc + 1]; - path[pathc] = 0; - - for (int k = 0; k < pathEntries.size(); ++k) { - QByteArray tmp = QFile::encodeName(pathEntries.at(k)); - if (!tmp.endsWith('/')) tmp += '/'; - tmp += encodedProgramName; - path[k] = ::strdup(tmp.constData()); - } - } - } - } - // Start the process manager, and fork off the child process. pid_t childPid; forkfd = ::forkfd(FFD_CLOEXEC, &childPid); @@ -473,16 +459,12 @@ void QProcessPrivate::startProcess() if (forkfd != FFD_CHILD_PROCESS) { // Parent process. // Clean up duplicated memory. - free(dupProgramName); - for (int i = 1; i <= arguments.count(); ++i) + for (int i = 0; i <= arguments.count(); ++i) free(argv[i]); for (int i = 0; i < envc; ++i) free(envp[i]); - for (int i = 0; i < pathc; ++i) - free(path[i]); delete [] argv; delete [] envp; - delete [] path; } // On QNX, if spawnChild failed, childPid will be -1 but forkfd is still 0. @@ -503,7 +485,7 @@ void QProcessPrivate::startProcess() // Start the child. if (forkfd == FFD_CHILD_PROCESS) { - execChild(workingDirPtr, path, argv, envp); + execChild(workingDirPtr, argv, envp); ::_exit(-1); } @@ -544,7 +526,7 @@ void QProcessPrivate::startProcess() } } -void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv, char **envp) +void QProcessPrivate::execChild(const char *workingDir, char **argv, char **envp) { ::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored @@ -567,7 +549,7 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv } } - // make sure this fd is closed if execvp() succeeds + // make sure this fd is closed if execv() succeeds qt_safe_close(childStartedPipe[0]); // enter the working directory @@ -582,25 +564,13 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv // execute the process if (!envp) { - qt_safe_execvp(argv[0], argv); - callthatfailed = "execvp: "; + qt_safe_execv(argv[0], argv); + callthatfailed = "execv: "; } else { - if (path) { - char **arg = path; - while (*arg) { - argv[0] = *arg; -#if defined (QPROCESS_DEBUG) - fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n", argv[0]); -#endif - qt_safe_execve(argv[0], argv, envp); - ++arg; - } - } else { #if defined (QPROCESS_DEBUG) - fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]); + fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]); #endif - qt_safe_execve(argv[0], argv, envp); - } + qt_safe_execve(argv[0], argv, envp); callthatfailed = "execve: "; } @@ -925,7 +895,7 @@ bool QProcessPrivate::waitForDeadChild() return true; } -bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) +bool QProcessPrivate::startDetached(qint64 *pid) { QByteArray encodedWorkingDirectory = QFile::encodeName(workingDirectory); @@ -967,23 +937,28 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData()); argv[arguments.size() + 1] = 0; + // Duplicate the environment. + int envc = 0; + char **envp = nullptr; + if (environment.d.constData()) { + QProcessEnvironmentPrivate::MutexLocker locker(environment.d); + envp = _q_dupEnvironment(environment.d.constData()->hash, &envc); + } + + QByteArray tmp; if (!program.contains(QLatin1Char('/'))) { - const QString path = QString::fromLocal8Bit(qgetenv("PATH")); - if (!path.isEmpty()) { - QStringList pathEntries = path.split(QLatin1Char(':')); - for (int k = 0; k < pathEntries.size(); ++k) { - QByteArray tmp = QFile::encodeName(pathEntries.at(k)); - if (!tmp.endsWith('/')) tmp += '/'; - tmp += QFile::encodeName(program); - argv[0] = tmp.data(); - qt_safe_execv(argv[0], argv); - } - } - } else { - QByteArray tmp = QFile::encodeName(program); - argv[0] = tmp.data(); - qt_safe_execv(argv[0], argv); + const QString &exeFilePath = QStandardPaths::findExecutable(program); + if (!exeFilePath.isEmpty()) + tmp = QFile::encodeName(exeFilePath); } + if (tmp.isEmpty()) + tmp = QFile::encodeName(program); + argv[0] = tmp.data(); + + if (envp) + qt_safe_execve(argv[0], argv, envp); + else + qt_safe_execv(argv[0], argv); struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 329d1842f0..cca910bcc0 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -358,7 +358,8 @@ void QProcessPrivate::closeChannel(Channel *channel) destroyPipe(channel->pipe); } -static QString qt_create_commandline(const QString &program, const QStringList &arguments) +static QString qt_create_commandline(const QString &program, const QStringList &arguments, + const QString &nativeArguments) { QString args; if (!program.isEmpty()) { @@ -387,6 +388,13 @@ static QString qt_create_commandline(const QString &program, const QStringList & } args += QLatin1Char(' ') + tmp; } + + if (!nativeArguments.isEmpty()) { + if (!args.isEmpty()) + args += QLatin1Char(' '); + args += nativeArguments; + } + return args; } @@ -472,15 +480,10 @@ void QProcessPrivate::startProcess() !openChannel(stderrChannel)) return; - QString args = qt_create_commandline(program, arguments); + const QString args = qt_create_commandline(program, arguments, nativeArguments); QByteArray envlist; if (environment.d.constData()) envlist = qt_create_environment(environment.d.constData()->hash); - if (!nativeArguments.isEmpty()) { - if (!args.isEmpty()) - args += QLatin1Char(' '); - args += nativeArguments; - } #if defined QPROCESS_DEBUG qDebug("Creating process"); @@ -826,6 +829,7 @@ bool QProcessPrivate::writeToStdin() // Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails // with ERROR_ELEVATION_REQUIRED. static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments, + const QString &nativeArguments, const QString &workingDir, qint64 *pid) { typedef BOOL (WINAPI *ShellExecuteExType)(SHELLEXECUTEINFOW *); @@ -836,7 +840,8 @@ static bool startDetachedUacPrompt(const QString &programIn, const QStringList & if (!shellExecuteEx) return false; - const QString args = qt_create_commandline(QString(), arguments); // needs arguments only + const QString args = qt_create_commandline(QString(), // needs arguments only + arguments, nativeArguments); SHELLEXECUTEINFOW shellExecuteExInfo; memset(&shellExecuteExInfo, 0, sizeof(SHELLEXECUTEINFOW)); shellExecuteExInfo.cbSize = sizeof(SHELLEXECUTEINFOW); @@ -859,14 +864,21 @@ static bool startDetachedUacPrompt(const QString &programIn, const QStringList & return true; } -bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid) +bool QProcessPrivate::startDetached(qint64 *pid) { static const DWORD errorElevationRequired = 740; - QString args = qt_create_commandline(program, arguments); + QString args = qt_create_commandline(program, arguments, nativeArguments); bool success = false; PROCESS_INFORMATION pinfo; + void *envPtr = nullptr; + QByteArray envlist; + if (environment.d.constData()) { + envlist = qt_create_environment(environment.d.constData()->hash); + envPtr = envlist.data(); + } + DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW); dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, @@ -875,8 +887,8 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; success = CreateProcess(0, (wchar_t*)args.utf16(), - 0, 0, FALSE, dwCreationFlags, 0, - workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(), + 0, 0, FALSE, dwCreationFlags, envPtr, + workingDirectory.isEmpty() ? 0 : (wchar_t*)workingDirectory.utf16(), &startupInfo, &pinfo); if (success) { @@ -885,7 +897,10 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a if (pid) *pid = pinfo.dwProcessId; } else if (GetLastError() == errorElevationRequired) { - success = startDetachedUacPrompt(program, arguments, workingDir, pid); + if (envPtr) + qWarning("QProcess: custom environment will be ignored for detached elevated process."); + success = startDetachedUacPrompt(program, arguments, nativeArguments, + workingDirectory, pid); } return success; diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 32639759e4..984ed23812 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -66,10 +66,9 @@ QT_BEGIN_NAMESPACE class QStringSplitter { public: - QStringSplitter(const QString &s) - : m_string(s), m_data(m_string.constData()), m_len(s.length()), m_pos(0) + explicit QStringSplitter(QStringView sv) + : m_data(sv.data()), m_len(sv.size()) { - m_splitChar = QLatin1Char('/'); } inline bool hasNext() { @@ -78,18 +77,17 @@ public: return m_pos < m_len; } - inline QStringRef next() { + inline QStringView next() { int start = m_pos; while (m_pos < m_len && m_data[m_pos] != m_splitChar) ++m_pos; - return QStringRef(&m_string, start, m_pos - start); + return QStringView(m_data + start, m_pos - start); } - QString m_string; const QChar *m_data; - QChar m_splitChar; - int m_len; - int m_pos; + qssize_t m_len; + qssize_t m_pos = 0; + QChar m_splitChar = QLatin1Char('/'); }; @@ -678,7 +676,7 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const QStringSplitter splitter(path); while (child_count && splitter.hasNext()) { - QStringRef segment = splitter.next(); + QStringView segment = splitter.next(); #ifdef DEBUG_RESOURCE_MATCH qDebug() << " CHILDREN" << segment; @@ -835,24 +833,24 @@ QStringList QResourceRoot::children(int node) const bool QResourceRoot::mappingRootSubdir(const QString &path, QString *match) const { const QString root = mappingRoot(); - if(!root.isEmpty()) { - const QVector<QStringRef> root_segments = root.splitRef(QLatin1Char('/'), QString::SkipEmptyParts), - path_segments = path.splitRef(QLatin1Char('/'), QString::SkipEmptyParts); - if(path_segments.size() <= root_segments.size()) { - int matched = 0; - for(int i = 0; i < path_segments.size(); ++i) { - if(root_segments[i] != path_segments[i]) - break; - ++matched; - } - if(matched == path_segments.size()) { - if(match && root_segments.size() > matched) - *match = root_segments.at(matched).toString(); - return true; - } + if (root.isEmpty()) + return false; + + QStringSplitter rootIt(root); + QStringSplitter pathIt(path); + while (rootIt.hasNext()) { + if (pathIt.hasNext()) { + if (rootIt.next() != pathIt.next()) // mismatch + return false; + } else { + // end of path, but not of root: + if (match) + *match = rootIt.next().toString(); + return true; } } - return false; + // end of root + return !pathIt.hasNext(); } Q_CORE_EXPORT bool qRegisterResourceData(int version, const unsigned char *tree, diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index 16dab38a60..24fa00c4d9 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -1802,6 +1802,8 @@ struct QSettingsIniSection inline QSettingsIniSection() : position(-1) {} }; +Q_DECLARE_TYPEINFO(QSettingsIniSection, Q_MOVABLE_TYPE); + typedef QMap<QString, QSettingsIniSection> IniMap; /* diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h index 639605d8c4..d8e91e48ce 100644 --- a/src/corelib/io/qsettings_p.h +++ b/src/corelib/io/qsettings_p.h @@ -109,6 +109,8 @@ private: }; #endif +Q_DECLARE_TYPEINFO(QSettingsKey, Q_MOVABLE_TYPE); + typedef QMap<QSettingsKey, QByteArray> UnparsedSettingsMap; typedef QMap<QSettingsKey, QVariant> ParsedSettingsMap; diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h index 7f365f0e8a..bf40e1627a 100644 --- a/src/corelib/io/qtemporaryfile_p.h +++ b/src/corelib/io/qtemporaryfile_p.h @@ -65,7 +65,7 @@ class QTemporaryFilePrivate : public QFilePrivate { Q_DECLARE_PUBLIC(QTemporaryFile) -protected: +public: QTemporaryFilePrivate(); explicit QTemporaryFilePrivate(const QString &templateNameIn); ~QTemporaryFilePrivate(); diff --git a/src/corelib/io/qtldurl.cpp b/src/corelib/io/qtldurl.cpp index 96543bbbfd..a934d19fa2 100644 --- a/src/corelib/io/qtldurl.cpp +++ b/src/corelib/io/qtldurl.cpp @@ -50,9 +50,21 @@ QT_BEGIN_NAMESPACE -static bool containsTLDEntry(const QStringRef &entry) +enum TLDMatchType { + ExactMatch, + SuffixMatch, + ExceptionMatch, +}; + +static bool containsTLDEntry(QStringView entry, TLDMatchType match) { - int index = qt_hash(entry) % tldCount; + const QStringView matchSymbols[] = { + QStringViewLiteral(""), + QStringViewLiteral("*"), + QStringViewLiteral("!"), + }; + const auto symbol = matchSymbols[match]; + int index = qt_hash(entry, qt_hash(symbol)) % tldCount; // select the right chunk from the big table short chunk = 0; @@ -65,19 +77,14 @@ static bool containsTLDEntry(const QStringRef &entry) // check all the entries from the given index while (chunkIndex < tldIndices[index+1] - offset) { - QString currentEntry = QString::fromUtf8(tldData[chunk] + chunkIndex); - if (currentEntry == entry) + const auto utf8 = tldData[chunk] + chunkIndex; + if ((symbol.isEmpty() || QLatin1Char(*utf8) == symbol) && entry == QString::fromUtf8(utf8 + symbol.size())) return true; - chunkIndex += qstrlen(tldData[chunk] + chunkIndex) + 1; // +1 for the ending \0 + chunkIndex += qstrlen(utf8) + 1; // +1 for the ending \0 } return false; } -static inline bool containsTLDEntry(const QString &entry) -{ - return containsTLDEntry(QStringRef(&entry)); -} - /*! \internal @@ -111,19 +118,16 @@ Q_CORE_EXPORT bool qIsEffectiveTLD(const QStringRef &domain) { // for domain 'foo.bar.com': // 1. return if TLD table contains 'foo.bar.com' - if (containsTLDEntry(domain)) + // 2. else if table contains '*.bar.com', + // 3. test that table does not contain '!foo.bar.com' + + if (containsTLDEntry(domain, ExactMatch)) // 1 return true; const int dot = domain.indexOf(QLatin1Char('.')); if (dot >= 0) { - int count = domain.size() - dot; - QString wildCardDomain = QLatin1Char('*') + domain.right(count); - // 2. if table contains '*.bar.com', - // test if table contains '!foo.bar.com' - if (containsTLDEntry(wildCardDomain)) { - QString exceptionDomain = QLatin1Char('!') + domain; - return (! containsTLDEntry(exceptionDomain)); - } + if (containsTLDEntry(domain.mid(dot), SuffixMatch)) // 2 + return !containsTLDEntry(domain, ExceptionMatch); // 3 } return false; } |