diff options
author | Shane Kearns <shane.kearns@sosco.com> | 2009-08-24 07:36:20 (GMT) |
---|---|---|
committer | Shane Kearns <shane.kearns@sosco.com> | 2009-08-24 07:36:20 (GMT) |
commit | 898cba2245b6fafa3820b44203442fedd9f7ed73 (patch) | |
tree | c7545af2a15396c7c5d79612d7073de9b4274d43 /src/corelib/io | |
parent | 6dade01b24f3fd314cb6ec9c2979348e78740a52 (diff) | |
parent | 028655065de7f989a35b63bcab583767aba9c048 (diff) | |
download | Qt-898cba2245b6fafa3820b44203442fedd9f7ed73.zip Qt-898cba2245b6fafa3820b44203442fedd9f7ed73.tar.gz Qt-898cba2245b6fafa3820b44203442fedd9f7ed73.tar.bz2 |
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt-s60-public
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/qfile.cpp | 22 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine.cpp | 2 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_p.h | 4 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_unix.cpp | 72 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_win.cpp | 278 | ||||
-rw-r--r-- | src/corelib/io/qprocess.cpp | 394 | ||||
-rw-r--r-- | src/corelib/io/qprocess.h | 39 | ||||
-rw-r--r-- | src/corelib/io/qprocess_p.h | 19 | ||||
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 26 | ||||
-rw-r--r-- | src/corelib/io/qprocess_win.cpp | 19 | ||||
-rw-r--r-- | src/corelib/io/qresource.cpp | 6 |
11 files changed, 676 insertions, 205 deletions
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 5e1a5e7..026c1fd 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -52,10 +52,6 @@ # include "qcoreapplication.h" #endif -#if !defined(Q_OS_WINCE) -#include <errno.h> -#endif - #ifdef QT_NO_QOBJECT #define tr(X) QString::fromLatin1(X) #endif @@ -653,11 +649,7 @@ QFile::remove() unsetError(); return true; } -#if defined(Q_OS_WIN) - d->setError(QFile::RemoveError, GetLastError()); -#else - d->setError(QFile::RemoveError, errno); -#endif + d->setError(QFile::RemoveError, fileEngine()->errorString()); } return false; } @@ -812,7 +804,7 @@ QFile::link(const QString &linkName) unsetError(); return true; } - d->setError(QFile::RenameError, errno); + d->setError(QFile::RenameError, fileEngine()->errorString()); return false; } @@ -1258,7 +1250,7 @@ QFile::resize(qint64 sz) unsetError(); return true; } - d->setError(QFile::ResizeError, errno); + d->setError(QFile::ResizeError, fileEngine()->errorString()); return false; } @@ -1322,7 +1314,7 @@ QFile::setPermissions(Permissions permissions) unsetError(); return true; } - d->setError(QFile::PermissionsError, errno); + d->setError(QFile::PermissionsError, fileEngine()->errorString()); return false; } @@ -1478,7 +1470,7 @@ bool QFile::seek(qint64 off) d->setError(err, fileEngine()->errorString()); return false; } - d->error = NoError; + unsetError(); return true; } @@ -1506,7 +1498,7 @@ qint64 QFile::readLineData(char *data, qint64 maxlen) qint64 QFile::readData(char *data, qint64 len) { Q_D(QFile); - d->error = NoError; + unsetError(); if (!d->ensureFlushed()) return -1; @@ -1588,7 +1580,7 @@ qint64 QFile::writeData(const char *data, qint64 len) { Q_D(QFile); - d->error = NoError; + unsetError(); d->lastWasWrite = true; bool buffered = !(d->openMode & Unbuffered); diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 3d109d1..1ca19cf 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -109,7 +109,7 @@ void QFSFileEnginePrivate::init() { is_sequential = 0; tried_stat = 0; -#ifdef Q_OS_UNIX +#if !defined(Q_OS_WINCE) need_lstat = 1; is_link = 0; #endif diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index 15cbf5c..b245dca 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -137,10 +137,11 @@ public: mutable uint is_sequential : 2; mutable uint could_stat : 1; mutable uint tried_stat : 1; -#ifdef Q_OS_UNIX +#if !defined(Q_OS_WINCE) mutable uint need_lstat : 1; mutable uint is_link : 1; #endif + bool doStat() const; bool isSymlink() const; @@ -161,7 +162,6 @@ protected: #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) QAbstractFileEngine::FileFlags getPermissions() const; - QString getLink() const; #endif }; diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 62edb0e..4a485bb 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -393,7 +393,10 @@ bool QFSFileEnginePrivate::nativeIsSequential() const bool QFSFileEngine::remove() { Q_D(QFSFileEngine); - return unlink(d->nativeFilePath.constData()) == 0; + bool ret = unlink(d->nativeFilePath.constData()) == 0; + if (!ret) + setError(QFile::RemoveError, qt_error_string(errno)); + return ret; } bool QFSFileEngine::copy(const QString &newName) @@ -421,6 +424,7 @@ bool QFSFileEngine::copy(const QString &newName) return (err == KErrNone); #else // ### Add copy code for Unix here + setError(QFile::UnspecifiedError, QLatin1String("Not implemented!")); return false; #endif } @@ -428,13 +432,19 @@ bool QFSFileEngine::copy(const QString &newName) bool QFSFileEngine::rename(const QString &newName) { Q_D(QFSFileEngine); - return ::rename(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0; + bool ret = ::rename(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0; + if (!ret) + setError(QFile::RenameError, qt_error_string(errno)); + return ret; } bool QFSFileEngine::link(const QString &newName) { Q_D(QFSFileEngine); - return ::symlink(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0; + bool ret = ::symlink(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0; + if (!ret) + setError(QFile::RenameError, qt_error_string(errno)); + return ret; } qint64 QFSFileEnginePrivate::nativeSize() const @@ -583,21 +593,21 @@ QString QFSFileEngine::homePath() QString QFSFileEngine::rootPath() { #if defined(Q_OS_SYMBIAN) - return QString::fromLatin1("C:/"); + return QLatin1String("C:/"); #else - return QString::fromLatin1("/"); + return QLatin1String("/"); #endif } QString QFSFileEngine::tempPath() { #ifdef Q_OS_SYMBIAN - QString temp = QDir::currentPath().left(2); - temp += QString::fromLatin1( "/system/temp/"); + QString temp = QDir::currentPath().left(2); + temp += QLatin1String("/system/temp/"); #else - QString temp = QFile::decodeName(qgetenv("TMPDIR")); - if (temp.isEmpty()) - temp = QString::fromLatin1("/tmp/"); + QString temp = QFile::decodeName(qgetenv("TMPDIR")); + if (temp.isEmpty()) + temp = QLatin1String("/tmp/"); #endif return temp; } @@ -620,7 +630,7 @@ QFileInfoList QFSFileEngine::drives() qWarning("QDir::drives: Getting drives failed"); } #else - ret.append(rootPath()); + ret.append(QFileInfo(rootPath())); #endif return ret; } @@ -767,11 +777,11 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const else if (exists && (d->st.st_mode & S_IFMT) == S_IFDIR) ret |= DirectoryType; #if !defined(QWS) && defined(Q_OS_MAC) - if((ret & DirectoryType) && (type & BundleType)) { + if ((ret & DirectoryType) && (type & BundleType)) { QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(d->filePath), kCFURLPOSIXPathStyle, true); UInt32 type, creator; - if(CFBundleGetPackageInfoInDirectory(url, &type, &creator)) + if (CFBundleGetPackageInfoInDirectory(url, &type, &creator)) ret |= BundleType; } #endif @@ -932,9 +942,9 @@ QString QFSFileEngine::fileName(FileName file) const #if !defined(QWS) && defined(Q_OS_MAC) QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(d->filePath), kCFURLPOSIXPathStyle, true); - if(CFDictionaryRef dict = CFBundleCopyInfoDictionaryForURL(url)) { - if(CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) { - if(CFGetTypeID(name) == CFStringGetTypeID()) + if (CFDictionaryRef dict = CFBundleCopyInfoDictionaryForURL(url)) { + if (CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) { + if (CFGetTypeID(name) == CFStringGetTypeID()) return QCFString::toQString((CFStringRef)name); } } @@ -1142,6 +1152,7 @@ QString QFSFileEngine::owner(FileOwner own) const bool QFSFileEngine::setPermissions(uint perms) { Q_D(QFSFileEngine); + bool ret = false; mode_t mode = 0; if (perms & ReadOwnerPerm) mode |= S_IRUSR; @@ -1168,18 +1179,27 @@ bool QFSFileEngine::setPermissions(uint perms) if (perms & ExeOtherPerm) mode |= S_IXOTH; if (d->fd != -1) - return !fchmod(d->fd, mode); - return !::chmod(d->nativeFilePath.constData(), mode); + ret = fchmod(d->fd, mode) == 0; + else + ret = ::chmod(d->nativeFilePath.constData(), mode) == 0; + if (!ret) + setError(QFile::PermissionsError, qt_error_string(errno)); + return ret; } bool QFSFileEngine::setSize(qint64 size) { Q_D(QFSFileEngine); + bool ret = false; if (d->fd != -1) - return !QT_FTRUNCATE(d->fd, size); - if (d->fh) - return !QT_FTRUNCATE(QT_FILENO(d->fh), size); - return !QT_TRUNCATE(d->nativeFilePath.constData(), size); + ret = QT_FTRUNCATE(d->fd, size) == 0; + else if (d->fh) + ret = QT_FTRUNCATE(QT_FILENO(d->fh), size) == 0; + else + ret = QT_TRUNCATE(d->nativeFilePath.constData(), size) == 0; + if (!ret) + setError(QFile::ResizeError, qt_error_string(errno)); + return ret; } QDateTime QFSFileEngine::fileTime(FileTime time) const @@ -1201,14 +1221,14 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla { Q_Q(QFSFileEngine); Q_UNUSED(flags); - if (offset < 0) { - q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL))); - return 0; - } if (openMode == QIODevice::NotOpen) { q->setError(QFile::PermissionsError, qt_error_string(int(EACCES))); return 0; } + if (offset < 0) { + q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL))); + return 0; + } int access = 0; if (openMode & QIODevice::ReadOnly) access |= PROT_READ; if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE; diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index e01b42b..f1f69e7 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -55,6 +55,7 @@ #if !defined(Q_OS_WINCE) # include <sys/types.h> # include <direct.h> +# include <winioctl.h> #else # include <types.h> #endif @@ -88,6 +89,37 @@ typedef INT_PTR intptr_t; # define INVALID_FILE_ATTRIBUTES (DWORD (-1)) #endif +#if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) && !defined(Q_OS_WINCE) +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +# define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) +# define MAXIMUM_REPARSE_DATA_BUFFER_SIZE 16384 +#endif + QT_BEGIN_NAMESPACE static QString readLink(const QString &link); @@ -122,7 +154,7 @@ QT_END_INCLUDE_NAMESPACE void QFSFileEnginePrivate::resolveLibs() { static bool triedResolve = false; - if(!triedResolve) { + if (!triedResolve) { // need to resolve the security info functions // protect initialization @@ -130,7 +162,7 @@ void QFSFileEnginePrivate::resolveLibs() QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); // check triedResolve again, since another thread may have already // done the initialization - if(triedResolve) { + if (triedResolve) { // another thread did initialize the security function pointers, // so we shouldn't do it again. return; @@ -219,7 +251,7 @@ bool QFSFileEnginePrivate::uncListSharesOnServer(const QString &server, QStringL if (resolveUNCLibs()) { SHARE_INFO_1 *BufPtr, *p; DWORD res; - DWORD er=0,tr=0,resume=0, i; + DWORD er = 0, tr = 0, resume = 0, i; do { res = ptrNetShareEnum((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume); if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) { @@ -231,7 +263,7 @@ bool QFSFileEnginePrivate::uncListSharesOnServer(const QString &server, QStringL } } ptrNetApiBufferFree(BufPtr); - } while (res==ERROR_MORE_DATA); + } while (res == ERROR_MORE_DATA); return res == ERROR_SUCCESS; } return false; @@ -780,21 +812,30 @@ bool QFSFileEnginePrivate::nativeIsSequential() const bool QFSFileEngine::remove() { Q_D(QFSFileEngine); - return ::DeleteFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16()) != 0; + bool ret = ::DeleteFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16()) != 0; + if (!ret) + setError(QFile::RemoveError, qt_error_string()); + return ret; } bool QFSFileEngine::copy(const QString ©Name) { Q_D(QFSFileEngine); - return ::CopyFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), - (wchar_t*)QFSFileEnginePrivate::longFileName(copyName).utf16(), true) != 0; + bool ret = ::CopyFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), + (wchar_t*)QFSFileEnginePrivate::longFileName(copyName).utf16(), true) != 0; + if (!ret) + setError(QFile::CopyError, qt_error_string()); + return ret; } bool QFSFileEngine::rename(const QString &newName) { Q_D(QFSFileEngine); - return ::MoveFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), - (wchar_t*)QFSFileEnginePrivate::longFileName(newName).utf16()) != 0; + bool ret = ::MoveFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), + (wchar_t*)QFSFileEnginePrivate::longFileName(newName).utf16()) != 0; + if (!ret) + setError(QFile::RenameError, qt_error_string()); + return ret; } static inline bool mkDir(const QString &path) @@ -884,7 +925,7 @@ bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) con for (int slash=0; slash != -1; oldslash = slash) { slash = dirName.indexOf(QDir::separator(), oldslash+1); if (slash == -1) { - if(oldslash == dirName.length()) + if (oldslash == dirName.length()) break; slash = dirName.length(); } @@ -939,8 +980,8 @@ bool QFSFileEngine::setCurrentPath(const QString &path) #if !defined(Q_OS_WINCE) return ::SetCurrentDirectory((wchar_t*)path.utf16()) != 0; #else - qfsPrivateCurrentDir = QFSFileEnginePrivate::longFileName(path); - return true; + qfsPrivateCurrentDir = QFSFileEnginePrivate::longFileName(path); + return true; #endif } @@ -978,9 +1019,9 @@ QString QFSFileEngine::currentPath(const QString &fileName) ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters. return QDir::fromNativeSeparators(ret); #else - Q_UNUSED(fileName); - if (qfsPrivateCurrentDir.isEmpty()) - qfsPrivateCurrentDir = QCoreApplication::applicationDirPath(); + Q_UNUSED(fileName); + if (qfsPrivateCurrentDir.isEmpty()) + qfsPrivateCurrentDir = QCoreApplication::applicationDirPath(); return QDir::fromNativeSeparators(qfsPrivateCurrentDir); #endif @@ -1012,15 +1053,15 @@ QString QFSFileEngine::homePath() } } #endif - if(ret.isEmpty() || !QFile::exists(ret)) { + if (ret.isEmpty() || !QFile::exists(ret)) { ret = QString::fromLocal8Bit(qgetenv("USERPROFILE").constData()); - if(ret.isEmpty() || !QFile::exists(ret)) { + if (ret.isEmpty() || !QFile::exists(ret)) { ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE").constData()) + QString::fromLocal8Bit(qgetenv("HOMEPATH").constData()); - if(ret.isEmpty() || !QFile::exists(ret)) { + if (ret.isEmpty() || !QFile::exists(ret)) { ret = QString::fromLocal8Bit(qgetenv("HOME").constData()); - if(ret.isEmpty() || !QFile::exists(ret)) { + if (ret.isEmpty() || !QFile::exists(ret)) { #if defined(Q_OS_WINCE) - ret = QString::fromLatin1("\\My Documents"); + ret = QLatin1String("\\My Documents"); if (!QFile::exists(ret)) #endif ret = rootPath(); @@ -1034,12 +1075,12 @@ QString QFSFileEngine::homePath() QString QFSFileEngine::rootPath() { #if defined(Q_OS_WINCE) - QString ret = QString::fromLatin1("/"); + QString ret = QLatin1String("/"); #elif defined(Q_FS_FAT) QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData()); - if(ret.isEmpty()) + if (ret.isEmpty()) ret = QLatin1String("c:"); - ret += QLatin1Char('/'); + ret.append(QLatin1Char('/')); #elif defined(Q_OS_OS2EMX) char dir[4]; _abspath(dir, QLatin1String("/"), _MAX_PATH); @@ -1050,20 +1091,23 @@ QString QFSFileEngine::rootPath() QString QFSFileEngine::tempPath() { - wchar_t tempPath[MAX_PATH]; - int success = GetTempPath(MAX_PATH, tempPath); - QString ret = QString::fromWCharArray(tempPath); - - if (ret.isEmpty() || !success) { + QString ret; + { + wchar_t tempPath[MAX_PATH]; + if (GetTempPath(MAX_PATH, tempPath)) + ret = QString::fromWCharArray(tempPath); + if (!ret.isEmpty()) { + while (ret.endsWith(QLatin1Char('\\'))) + ret.chop(1); + ret = QDir::fromNativeSeparators(ret); + } + } + if (ret.isEmpty()) { #if !defined(Q_OS_WINCE) - ret = QString::fromLatin1("c:/tmp"); + ret = QLatin1String("c:/tmp"); #else - ret = QString::fromLatin1("\\Temp"); + ret = QLatin1String("/Temp"); #endif - } else { - ret = QDir::fromNativeSeparators(ret); - while (ret.at(ret.length()-1) == QLatin1Char('/')) - ret = ret.left(ret.length()-1); } return ret; } @@ -1076,21 +1120,21 @@ QFileInfoList QFSFileEngine::drives() quint32 driveBits = (quint32) GetLogicalDrives() & 0x3ffffff; #elif defined(Q_OS_OS2EMX) quint32 driveBits, cur; - if(DosQueryCurrentDisk(&cur,&driveBits) != NO_ERROR) + if (DosQueryCurrentDisk(&cur, &driveBits) != NO_ERROR) exit(1); driveBits &= 0x3ffffff; #endif char driveName[] = "A:/"; - while(driveBits) { - if(driveBits & 1) - ret.append(QString::fromLatin1(driveName)); + while (driveBits) { + if (driveBits & 1) + ret.append(QFileInfo(QLatin1String(driveName))); driveName[0]++; driveBits = driveBits >> 1; } return ret; #else - ret.append(QString::fromLatin1("/")); + ret.append(QFileInfo(QLatin1String("/"))); return ret; #endif } @@ -1103,10 +1147,11 @@ bool QFSFileEnginePrivate::doStat() const if (filePath.isEmpty()) return could_stat; + QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; fname = fixIfRelativeUncPath(fname); - UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); if (fd != -1) { #if !defined(Q_OS_WINCE) @@ -1195,12 +1240,51 @@ bool QFSFileEnginePrivate::doStat() const #endif } } + SetErrorMode(oldmode); } return could_stat; } +static QString readSymLink(const QString &link) +{ + QString result; +#if !defined(Q_OS_WINCE) + HANDLE handle = CreateFile((wchar_t*)QFSFileEnginePrivate::longFileName(link).utf16(), + FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + 0); + if (handle != INVALID_HANDLE_VALUE) { + DWORD bufsize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; + REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)qMalloc(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) { + int length = rdb->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t); + int offset = rdb->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + const wchar_t* PathBuffer = &rdb->MountPointReparseBuffer.PathBuffer[offset]; + result = QString::fromWCharArray(PathBuffer, length); + } else { + int length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); + int offset = rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset]; + result = QString::fromWCharArray(PathBuffer, length); + } + // cut-off "//?/" and "/??/" + if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\')) + result = result.mid(4); + } + qFree(rdb); + CloseHandle(handle); + } +#endif // Q_OS_WINCE + return result; +} + static QString readLink(const QString &link) { #if !defined(Q_OS_WINCE) @@ -1224,11 +1308,11 @@ static QString readLink(const QString &link) if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface. IPersistFile *ppf; hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); - if(SUCCEEDED(hres)) { + if (SUCCEEDED(hres)) { hres = ppf->Load((LPOLESTR)link.utf16(), STGM_READ); //The original path of the link is retrieved. If the file/folder //was moved, the return value still have the old path. - if(SUCCEEDED(hres)) { + if (SUCCEEDED(hres)) { if (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR) ret = QString::fromWCharArray(szGotPath); } @@ -1258,14 +1342,6 @@ static QString readLink(const QString &link) #endif // Q_OS_WINCE } -/*! - \internal -*/ -QString QFSFileEnginePrivate::getLink() const -{ - return readLink(filePath); -} - bool QFSFileEngine::link(const QString &newName) { #if !defined(Q_OS_WINCE) @@ -1303,8 +1379,11 @@ bool QFSFileEngine::link(const QString &newName) } psl->Release(); } - if(neededCoInit) - CoUninitialize(); + if (!ret) + setError(QFile::RenameError, qt_error_string()); + + if (neededCoInit) + CoUninitialize(); return ret; #else @@ -1319,7 +1398,10 @@ bool QFSFileEngine::link(const QString &newName) // Need to append on our own orgName.prepend(QLatin1Char('"')); orgName.append(QLatin1Char('"')); - return SUCCEEDED(SHCreateShortcut((wchar_t*)linkName.utf16(), (wchar_t*)orgName.utf16())); + bool ret = SUCCEEDED(SHCreateShortcut((wchar_t*)linkName.utf16(), (wchar_t*)orgName.utf16())); + if (!ret) + setError(QFile::RenameError, qt_error_string()); + return ret; #endif // Q_OS_WINCE } @@ -1425,6 +1507,41 @@ QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions() const } /*! + \internal +*/ +bool QFSFileEnginePrivate::isSymlink() const +{ +#if !defined(Q_OS_WINCE) + if (need_lstat) { + need_lstat = false; + is_link = false; + + if (fileAttrib & FILE_ATTRIBUTE_REPARSE_POINT) { + QString path = QDir::toNativeSeparators(filePath); + // path for the FindFirstFile should not end with a trailing slash + while (path.endsWith(QLatin1Char('\\'))) + path.chop(1); + + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), + &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + if ((findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + && (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT + || findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + is_link = true; + } + } + } + } + return is_link; +#else + return false; +#endif // Q_OS_WINCE +} + +/*! \reimp */ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const @@ -1434,6 +1551,9 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil // Force a stat, so that we're guaranteed to get up-to-date results if (type & Refresh) { d->tried_stat = 0; +#if !defined(Q_OS_WINCE) + d->need_lstat = 1; +#endif } if (type & PermsMask) { @@ -1457,7 +1577,7 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil ret |= FileType; } } else if (d->doStat()) { - if (d->fileAttrib & FILE_ATTRIBUTE_REPARSE_POINT) + if ((type & LinkType) && d->isSymlink()) ret |= LinkType; if (d->fileAttrib & FILE_ATTRIBUTE_DIRECTORY) { ret |= DirectoryType; @@ -1485,32 +1605,32 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil QString QFSFileEngine::fileName(FileName file) const { Q_D(const QFSFileEngine); - if(file == BaseName) { + if (file == BaseName) { int slash = d->filePath.lastIndexOf(QLatin1Char('/')); - if(slash == -1) { + if (slash == -1) { int colon = d->filePath.lastIndexOf(QLatin1Char(':')); - if(colon != -1) + if (colon != -1) return d->filePath.mid(colon + 1); return d->filePath; } return d->filePath.mid(slash + 1); - } else if(file == PathName) { - if(!d->filePath.size()) + } else if (file == PathName) { + if (!d->filePath.size()) return d->filePath; int slash = d->filePath.lastIndexOf(QLatin1Char('/')); - if(slash == -1) { - if(d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) + if (slash == -1) { + if (d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) return d->filePath.left(2); return QString(QLatin1Char('.')); } else { - if(!slash) + if (!slash) return QString(QLatin1Char('/')); - if(slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) + if (slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) slash++; return d->filePath.left(slash); } - } else if(file == AbsoluteName || file == AbsolutePathName) { + } else if (file == AbsoluteName || file == AbsolutePathName) { QString ret; if (!isRelativePath()) { @@ -1524,7 +1644,7 @@ QString QFSFileEngine::fileName(FileName file) const ret = d->filePath; } #else - ret = d->filePath; + ret = d->filePath; #endif } else { ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->filePath); @@ -1553,7 +1673,7 @@ QString QFSFileEngine::fileName(FileName file) const return ret.left(slash > 0 ? slash : 1); } return ret; - } else if(file == CanonicalName || file == CanonicalPathName) { + } else if (file == CanonicalName || file == CanonicalPathName) { if (!(fileFlags(ExistsFlag) & ExistsFlag)) return QString(); @@ -1567,9 +1687,14 @@ QString QFSFileEngine::fileName(FileName file) const ret = ret.left(slash); } return ret; - } else if(file == LinkName) { - return QDir::fromNativeSeparators(d->getLink()); - } else if(file == BundleName) { + } else if (file == LinkName) { + QString ret; + if (d->filePath.endsWith(QLatin1String(".lnk"))) + ret = readLink(d->filePath); + else if (d->doStat() && d->isSymlink()) + ret = readSymLink(d->filePath); + return QDir::fromNativeSeparators(ret); + } else if (file == BundleName) { return QString(); } return d->filePath; @@ -1643,7 +1768,9 @@ bool QFSFileEngine::setPermissions(uint perms) if (mode == 0) // not supported return false; - ret = ::_wchmod((wchar_t*)d->longFileName(d->filePath).utf16(), mode) == 0; + ret = ::_wchmod((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), mode) == 0; + if (!ret) + setError(QFile::PermissionsError, qt_error_string(errno)); return ret; } @@ -1675,7 +1802,10 @@ bool QFSFileEngine::setSize(qint64 size) // resize file on disk QFile file(d->filePath); if (file.open(QFile::ReadWrite)) { - return file.resize(size); + bool ret = file.resize(size); + if (!ret) + setError(QFile::ResizeError, file.errorString()); + return ret; } } return false; @@ -1778,11 +1908,11 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, Q_Q(QFSFileEngine); Q_UNUSED(flags); if (openMode == QFile::NotOpen) { - q->setError(QFile::PermissionsError, qt_error_string()); + q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); return 0; } if (offset == 0 && size == 0) { - q->setError(QFile::UnspecifiedError, qt_error_string()); + q->setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER)); return 0; } @@ -1864,7 +1994,7 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) { Q_Q(QFSFileEngine); if (!maps.contains(ptr)) { - q->setError(QFile::PermissionsError, qt_error_string()); + q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); return false; } uchar *start = ptr - maps[ptr].first; diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 18ed676..057492d 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -101,27 +101,294 @@ QT_END_NAMESPACE QT_BEGIN_NAMESPACE -static QHash<QString, QString> environmentHashFromList(const QStringList &environment) +/*! + \class QProcessEnvironment + + \brief The QProcessEnvironment class holds the environment variables that + can be passed to a program. + + \ingroup io + \ingroup misc + \mainclass + \reentrant + \since 4.6 + + A process's environment is composed of a set of key=value pairs known as + environment variables. The QProcessEnvironment class wraps that concept + and allows easy manipulation of those variables. It's meant to be used + along with QProcess, to set the environment for child processes. It + cannot be used to change the current process's environment. + + The environment of the calling process can be obtained using + QProcessEnvironment::systemEnvironment(). + + On Unix systems, the variable names are case-sensitive. For that reason, + this class will not touch the names of the variables. Note as well that + Unix environment allows both variable names and contents to contain arbitrary + binary data (except for the NUL character), but this is not supported by + QProcessEnvironment. This class only supports names and values that are + encodable by the current locale settings (see QTextCodec::codecForLocale). + + On Windows, the variable names are case-insensitive. Therefore, + QProcessEnvironment will always uppercase the names and do case-insensitive + comparisons. + + On Windows CE, the concept of environment does not exist. This class will + keep the values set for compatibility with other platforms, but the values + set will have no effect on the processes being created. + + \sa QProcess, QProcess::systemEnvironment(), QProcess::setProcessEnvironment() +*/ +#ifdef Q_OS_WIN +static inline QProcessEnvironmentPrivate::Unit prepareName(const QString &name) +{ return name.toUpper(); } +static inline QProcessEnvironmentPrivate::Unit prepareName(const QByteArray &name) +{ return QString::fromLocal8Bit(name).toUpper(); } +static inline QString nameToString(const QProcessEnvironmentPrivate::Unit &name) +{ return name; } +static inline QProcessEnvironmentPrivate::Unit prepareValue(const QString &value) +{ return value; } +static inline QProcessEnvironmentPrivate::Unit prepareValue(const QByteArray &value) +{ return QString::fromLocal8Bit(value); } +static inline QString valueToString(const QProcessEnvironmentPrivate::Unit &value) +{ return value; } +static inline QByteArray valueToByteArray(const QProcessEnvironmentPrivate::Unit &value) +{ return value.toLocal8Bit(); } +#else +static inline QProcessEnvironmentPrivate::Unit prepareName(const QByteArray &name) +{ return name; } +static inline QProcessEnvironmentPrivate::Unit prepareName(const QString &name) +{ return name.toLocal8Bit(); } +static inline QString nameToString(const QProcessEnvironmentPrivate::Unit &name) +{ return QString::fromLocal8Bit(name); } +static inline QProcessEnvironmentPrivate::Unit prepareValue(const QByteArray &value) +{ return value; } +static inline QProcessEnvironmentPrivate::Unit prepareValue(const QString &value) +{ return value.toLocal8Bit(); } +static inline QString valueToString(const QProcessEnvironmentPrivate::Unit &value) +{ return QString::fromLocal8Bit(value); } +static inline QByteArray valueToByteArray(const QProcessEnvironmentPrivate::Unit &value) +{ return value; } +#endif + +template<> void QSharedDataPointer<QProcessEnvironmentPrivate>::detach() +{ + if (d && d->ref == 1) + return; + QProcessEnvironmentPrivate *x = (d ? new QProcessEnvironmentPrivate(*d) + : new QProcessEnvironmentPrivate); + x->ref.ref(); + if (d && !d->ref.deref()) + delete d; + d = x; +} + +QStringList QProcessEnvironmentPrivate::toList() const { - QHash<QString, QString> result; - QStringList::ConstIterator it = environment.constBegin(), - end = environment.constEnd(); + QStringList result; + QHash<Unit, Unit>::ConstIterator it = hash.constBegin(), + end = hash.constEnd(); for ( ; it != end; ++it) { - int equals = it->indexOf(QLatin1Char('=')); + QString data = nameToString(it.key()); + QString value = valueToString(it.value()); + data.reserve(data.length() + value.length() + 1); + data.append(QLatin1Char('=')); + data.append(value); + result << data; + } + return result; +} +QProcessEnvironment QProcessEnvironmentPrivate::fromList(const QStringList &list) +{ + QProcessEnvironment env; + QStringList::ConstIterator it = list.constBegin(), + end = list.constEnd(); + for ( ; it != end; ++it) { + int pos = it->indexOf(QLatin1Char('=')); + if (pos < 1) + continue; + + QString value = it->mid(pos + 1); QString name = *it; - QString value; - if (equals != -1) { - name.truncate(equals); -#ifdef Q_OS_WIN - name = name.toUpper(); -#endif - value = it->mid(equals + 1); - } - result.insert(name, value); + name.truncate(pos); + env.insert(name, value); } + return env; +} - return result; +/*! + Creates a new QProcessEnvironment object. This constructor creates an + empty environment. If set on a QProcess, this will cause the current + environment variables to be removed. +*/ +QProcessEnvironment::QProcessEnvironment() + : d(0) +{ +} + +/*! + Frees the resources associated with this QProcessEnvironment object. +*/ +QProcessEnvironment::~QProcessEnvironment() +{ +} + +/*! + Creates a QProcessEnvironment object that is a copy of \a other. +*/ +QProcessEnvironment::QProcessEnvironment(const QProcessEnvironment &other) + : d(other.d) +{ +} + +/*! + Copies the contents of the \a other QProcessEnvironment object into this + one. +*/ +QProcessEnvironment &QProcessEnvironment::operator=(const QProcessEnvironment &other) +{ + d = other.d; + return *this; +} + +/*! + \fn bool QProcessEnvironment::operator !=(const QProcessEnvironment &other) const + + Returns true if this and the \a other QProcessEnvironment objects are different. + + \sa operator==() +*/ + +/*! + Returns true if this and the \a other QProcessEnvironment objects are equal. + + Two QProcessEnvironment objects are considered equal if they have the same + set of key=value pairs. The comparison of keys is done case-sensitive on + platforms where the environment is case-sensitive. + + \sa operator!=(), contains() +*/ +bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const +{ + return d->hash == other.d->hash; +} + +/*! + Returns true if this QProcessEnvironment object is empty: that is + there are no key=value pairs set. + + \sa clear(), systemEnvironment(), insert() +*/ +bool QProcessEnvironment::isEmpty() const +{ + return d ? d->hash.isEmpty() : true; +} + +/*! + Removes all key=value pairs from this QProcessEnvironment object, making + it empty. + + \sa isEmpty(), systemEnvironment() +*/ +void QProcessEnvironment::clear() +{ + if (d) + d->hash.clear(); +} + +/*! + Returns true if the environment variable of name \a name is found in + this QProcessEnvironment object. + + On Windows, variable names are case-insensitive, so the key is converted + to uppercase before searching. On other systems, names are case-sensitive + so no trasformation is applied. + + \sa insert(), value() +*/ +bool QProcessEnvironment::contains(const QString &name) const +{ + return d ? d->hash.contains(prepareName(name)) : false; +} + +/*! + Inserts the environment variable of name \a name and contents \a value + into this QProcessEnvironment object. If that variable already existed, + it is replaced by the new value. + + On Windows, variable names are case-insensitive, so this function always + uppercases the variable name before inserting. On other systems, names + are case-sensitive, so no transformation is applied. + + On most systems, inserting a variable with no contents will have the + same effect for applications as if the variable had not been set at all. + However, to guarantee that there are no incompatibilities, to remove a + variable, please use the remove() function. + + \sa contains(), remove(), value() +*/ +void QProcessEnvironment::insert(const QString &name, const QString &value) +{ + d->hash.insert(prepareName(name), prepareValue(value)); +} + +/*! + Removes the environment variable identified by \a name from this + QProcessEnvironment object. If that variable did not exist before, + nothing happens. + + On Windows, variable names are case-insensitive, so the key is converted + to uppercase before searching. On other systems, names are case-sensitive + so no trasformation is applied. + + \sa contains(), insert(), value() +*/ +void QProcessEnvironment::remove(const QString &name) +{ + if (d) + d->hash.remove(prepareName(name)); +} + +/*! + Searches this QProcessEnvironment object for a variable identified by + \a name and returns its value. If the variable is not found in this object, + then \a defaultValue is returned instead. + + On Windows, variable names are case-insensitive, so the key is converted + to uppercase before searching. On other systems, names are case-sensitive + so no trasformation is applied. + + \sa contains(), insert(), remove() +*/ +QString QProcessEnvironment::value(const QString &name, const QString &defaultValue) const +{ + if (!d) + return defaultValue; + + QProcessEnvironmentPrivate::Hash::ConstIterator it = d->hash.constFind(prepareName(name)); + if (it == d->hash.constEnd()) + return defaultValue; + + return valueToString(it.value()); +} + +/*! + Converts this QProcessEnvironment object into a list of strings, one for + each environment variable that is set. The environment variable's name + and its value are separated by an equal character ('='). + + The QStringList contents returned by this function are suitable for use + with the QProcess::setEnvironment function. However, it is recommended + to use QProcess::setProcessEnvironment instead since that will avoid + unnecessary copying of the data. + + \sa systemEnvironment(), QProcess::systemEnvironment(), QProcess::environment(), + QProcess::setEnvironment() +*/ +QStringList QProcessEnvironment::toStringList() const +{ + return d ? d->toList() : QStringList(); } void QProcessPrivate::Channel::clear() @@ -451,7 +718,6 @@ QProcessPrivate::QProcessPrivate() sequenceNumber = 0; exitCode = 0; exitStatus = QProcess::NormalExit; - environment = 0; startupSocketNotifier = 0; deathNotifier = 0; notifier = 0; @@ -482,7 +748,6 @@ QProcessPrivate::QProcessPrivate() */ QProcessPrivate::~QProcessPrivate() { - delete environment; if (stdinChannel.process) stdinChannel.process->stdoutChannel.clear(); if (stdoutChannel.process) @@ -1235,6 +1500,7 @@ QProcess::ProcessState QProcess::state() const } /*! + \deprecated Sets the environment that QProcess will use when starting a process to the \a environment specified which consists of a list of key=value pairs. @@ -1243,14 +1509,18 @@ QProcess::ProcessState QProcess::state() const \snippet doc/src/snippets/qprocess-environment/main.cpp 0 - \sa environment(), systemEnvironment(), setEnvironmentHash() + \note This function is less efficient than the setProcessEnvironment() + function. + + \sa environment(), setProcessEnvironment(), systemEnvironment() */ void QProcess::setEnvironment(const QStringList &environment) { - setEnvironmentHash(environmentHashFromList(environment)); + setProcessEnvironment(QProcessEnvironmentPrivate::fromList(environment)); } /*! + \deprecated Returns the environment that QProcess will use when starting a process, or an empty QStringList if no environment has been set using setEnvironment() or setEnvironmentHash(). If no environment @@ -1259,67 +1529,50 @@ void QProcess::setEnvironment(const QStringList &environment) \note The environment settings are ignored on Windows CE and Symbian, as there is no concept of an environment. - \sa environmentHash(), setEnvironment(), systemEnvironment() + \sa processEnvironment(), setEnvironment(), systemEnvironment() */ QStringList QProcess::environment() const { Q_D(const QProcess); - - QStringList result; - if (!d->environment) - return result; - - QHash<QString, QString>::ConstIterator it = d->environment->constBegin(), - end = d->environment->constEnd(); - for ( ; it != end; ++it) { - QString data = it.key(); - data.reserve(data.length() + it.value().length() + 1); - data.append(QLatin1Char('=')); - data.append(it.value()); - result << data; - } - return result; + return d->environment.toStringList(); } /*! - \since 4.5 + \since 4.6 Sets the environment that QProcess will use when starting a process to the - \a environment hash map. + \a environment object. For example, the following code adds the \c{C:\\BIN} directory to the list of executable paths (\c{PATHS}) on Windows and sets \c{TMPDIR}: \snippet doc/src/snippets/qprocess-environment/main.cpp 1 - \sa environment(), systemEnvironmentHash(), setEnvironment() + Note how, on Windows, environment variable names are case-insensitive. + + \sa processEnvironment(), QProcessEnvironment::systemEnvironment(), setEnvironment() */ -void QProcess::setEnvironmentHash(const QHash<QString, QString> &environment) +void QProcess::setProcessEnvironment(const QProcessEnvironment &environment) { Q_D(QProcess); - if (!d->environment) - d->environment = new QHash<QString, QString>(environment); - else - *d->environment = environment; + d->environment = environment; } /*! - \since 4.5 + \since 4.6 Returns the environment that QProcess will use when starting a - process, or an empty QHash if no environment has been set using - setEnvironment() or setEnvironmentHash(). If no environment has + process, or an empty object if no environment has been set using + setEnvironment() or setProcessEnvironment(). If no environment has been set, the environment of the calling process will be used. \note The environment settings are ignored on Windows CE, as there is no concept of an environment. - \sa setEnvironmentHash(), setEnvironment(), systemEnvironmentHash() + \sa setProcessEnvironment(), setEnvironment(), QProcessEnvironment::isValid() */ -QHash<QString, QString> QProcess::environmentHash() const +QProcessEnvironment QProcess::processEnvironment() const { Q_D(const QProcess); - if (d->environment) - return *d->environment; - return QHash<QString, QString>(); + return d->environment; } /*! @@ -1924,7 +2177,16 @@ QT_END_INCLUDE_NAMESPACE \snippet doc/src/snippets/code/src_corelib_io_qprocess.cpp 8 - \sa systemEnvironmentHash(), environment(), setEnvironment() + This function does not cache the system environment. Therefore, it's + possible to obtain an updated version of the environment if low-level C + library functions like \tt setenv ot \tt putenv have been called. + + 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() + + \sa QProcessEnvironment::systemEnvironment(), environment(), setEnvironment() */ QStringList QProcess::systemEnvironment() { @@ -1937,15 +2199,33 @@ QStringList QProcess::systemEnvironment() } /*! - \since 4.5 + \since 4.6 + + Returns the environment of the calling process as a QProcessEnvironment. - Returns the environment of the calling process as a QHash. + This function does not cache the system environment. Therefore, it's + possible to obtain an updated version of the environment if low-level C + library functions like \tt setenv ot \tt putenv have been called. - \sa systemEnvironment(), environmentHash(), setEnvironmentHash() + However, note that repeated calls to this function will recreate the + QProcessEnvironment object, which is a non-trivial operation. + + \sa QProcess::systemEnvironment() */ -QHash<QString, QString> QProcess::systemEnvironmentHash() +QProcessEnvironment QProcessEnvironment::systemEnvironment() { - return environmentHashFromList(systemEnvironment()); + QProcessEnvironment env; + const char *entry; + for (int count = 0; (entry = environ[count]); ++count) { + const char *equal = strchr(entry, '='); + if (!equal) + continue; + + QByteArray name(entry, equal - entry); + QByteArray value(equal + 1); + env.insert(QString::fromLocal8Bit(name), QString::fromLocal8Bit(value)); + } + return env; } /*! diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 5faca5c..e0c7efb 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -44,6 +44,7 @@ #include <QtCore/qiodevice.h> #include <QtCore/qstringlist.h> +#include <QtCore/qshareddata.h> QT_BEGIN_HEADER @@ -53,8 +54,6 @@ QT_MODULE(Core) #ifndef QT_NO_PROCESS -template <class Key, class T> class QHash; - #if (!defined(Q_OS_WIN32) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)) || defined(qdoc) typedef qint64 Q_PID; #elif defined(Q_OS_SYMBIAN) @@ -69,6 +68,37 @@ QT_BEGIN_NAMESPACE #endif class QProcessPrivate; +class QProcessEnvironmentPrivate; + +class Q_CORE_EXPORT QProcessEnvironment +{ +public: + QProcessEnvironment(); + QProcessEnvironment(const QProcessEnvironment &other); + ~QProcessEnvironment(); + QProcessEnvironment &operator=(const QProcessEnvironment &other); + + bool operator==(const QProcessEnvironment &other) const; + inline bool operator!=(const QProcessEnvironment &other) const + { return !(*this == other); } + + bool isEmpty() const; + void clear(); + + bool contains(const QString &name) const; + void insert(const QString &name, const QString &value); + void remove(const QString &name); + QString value(const QString &name, const QString &defaultValue = QString()) const; + + QStringList toStringList() const; + + static QProcessEnvironment systemEnvironment(); + +private: + friend class QProcessPrivate; + friend class QProcessEnvironmentPrivate; + QSharedDataPointer<QProcessEnvironmentPrivate> d; +}; class Q_CORE_EXPORT QProcess : public QIODevice { @@ -128,8 +158,8 @@ public: void setEnvironment(const QStringList &environment); QStringList environment() const; - void setEnvironmentHash(const QHash<QString, QString> &environment); - QHash<QString, QString> environmentHash() const; + void setProcessEnvironment(const QProcessEnvironment &environment); + QProcessEnvironment processEnvironment() const; QProcess::ProcessError error() const; QProcess::ProcessState state() const; @@ -165,7 +195,6 @@ public: static bool startDetached(const QString &program); static QStringList systemEnvironment(); - static QHash<QString, QString> systemEnvironmentHash(); public Q_SLOTS: void terminate(); diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 34797b9..62a2ecc 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -55,6 +55,8 @@ #include "QtCore/qprocess.h" #include "QtCore/qstringlist.h" +#include "QtCore/qhash.h" +#include "QtCore/qshareddata.h" #include "private/qringbuffer_p.h" #include "private/qiodevice_p.h" @@ -76,6 +78,21 @@ class QWindowsPipeWriter; class QWinEventNotifier; class QTimer; +class QProcessEnvironmentPrivate: public QSharedData +{ +public: +#ifdef Q_OS_WIN + typedef QString Unit; +#else + typedef QByteArray Unit; +#endif + typedef QHash<Unit, Unit> Hash; + Hash hash; + + static QProcessEnvironment fromList(const QStringList &list); + QStringList toList() const; +}; + class QProcessPrivate : public QIODevicePrivate { public: @@ -161,7 +178,7 @@ public: QString program; QStringList arguments; - QHash<QString, QString> *environment; + QProcessEnvironment environment; QRingBuffer outputReadBuffer; QRingBuffer errorReadBuffer; diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index d28cdc4..dfeeb71 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -458,11 +458,11 @@ bool QProcessPrivate::createChannel(Channel &channel) } } -static char **_q_dupEnvironment(const QHash<QString, QString> *environment, int *envc) +static char **_q_dupEnvironment(const QHash<QByteArray, QByteArray> &environment, int *envc) { *envc = 0; - if (!environment) - return 0; // use the default environment + if (environment.isEmpty()) + return 0; // if LD_LIBRARY_PATH exists in the current environment, but // not in the environment list passed by the programmer, then @@ -474,17 +474,17 @@ static char **_q_dupEnvironment(const QHash<QString, QString> *environment, int #endif const QByteArray envLibraryPath = qgetenv(libraryPath); bool needToAddLibraryPath = !envLibraryPath.isEmpty() && - !environment->contains(QLatin1String(libraryPath)); + !environment.contains(libraryPath); - char **envp = new char *[environment->count() + 2]; - envp[environment->count()] = 0; - envp[environment->count() + 1] = 0; + char **envp = new char *[environment.count() + 2]; + envp[environment.count()] = 0; + envp[environment.count() + 1] = 0; - QHash<QString, QString>::ConstIterator it = environment->constBegin(); - const QHash<QString, QString>::ConstIterator end = environment->constEnd(); + QHash<QByteArray, QByteArray>::ConstIterator it = environment.constBegin(); + const QHash<QByteArray, QByteArray>::ConstIterator end = environment.constEnd(); for ( ; it != end; ++it) { - QByteArray key = it.key().toLocal8Bit(); - QByteArray value = it.value().toLocal8Bit(); + QByteArray key = it.key(); + QByteArray value = it.value(); key.reserve(key.length() + 1 + value.length()); key.append('='); key.append(value); @@ -590,7 +590,9 @@ void QProcessPrivate::startProcess() // Duplicate the environment. int envc = 0; - char **envp = _q_dupEnvironment(environment, &envc); + char **envp = 0; + if (environment.d.constData()) + envp = _q_dupEnvironment(environment.d.constData()->hash, &envc); // Encode the working directory if it's non-empty, otherwise just pass 0. const char *workingDirPtr = 0; diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index acb169f..8ece6ec 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -278,17 +278,17 @@ static QString qt_create_commandline(const QString &program, const QStringList & return args; } -static QByteArray qt_create_environment(const QHash<QString, QString> *environment) +static QByteArray qt_create_environment(const QHash<QString, QString> &environment) { QByteArray envlist; - if (environment) { - QHash<QString, QString> copy = *environment; + if (!environment.isEmpty()) { + QHash<QString, QString> copy = environment; // add PATH if necessary (for DLL loading) if (!copy.contains(QLatin1String("PATH"))) { QByteArray path = qgetenv("PATH"); if (!path.isEmpty()) - copy.insert(QLatin1String("PATH"), QString::fromLocal8Bit(path)); + copy.insert(QLatin1String("PATH"), QString::fromLocal8Bit(path)); } // add systemroot if needed @@ -362,7 +362,9 @@ void QProcessPrivate::startProcess() QString args = qt_create_commandline(QString(), arguments); #else QString args = qt_create_commandline(program, arguments); - QByteArray envlist = qt_create_environment(environment); + QByteArray envlist; + if (environment.d.constData()) + envlist = qt_create_environment(environment.d.constData()->hash); #endif #if defined QPROCESS_DEBUG @@ -393,9 +395,13 @@ void QProcessPrivate::startProcess() }; success = CreateProcess(0, (wchar_t*)args.utf16(), 0, 0, TRUE, dwCreationFlags, - environment ? envlist.data() : 0, + environment.isEmpty() ? 0 : envlist.data(), workingDirectory.isEmpty() ? 0 : (wchar_t*)QDir::toNativeSeparators(workingDirectory).utf16(), &startupInfo, pid); + if (!success) { + // Capture the error string before we do CloseHandle below + q->setErrorString(QProcess::tr("Process failed to start: %1").arg(qt_error_string())); + } if (stdinChannel.pipe[0] != INVALID_Q_PIPE) { CloseHandle(stdinChannel.pipe[0]); @@ -414,7 +420,6 @@ void QProcessPrivate::startProcess() if (!success) { cleanup(); processError = QProcess::FailedToStart; - q->setErrorString(QProcess::tr("Process failed to start")); emit q->error(processError); q->setProcessState(QProcess::NotRunning); return; diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index ab4a7b7..ff1a31f 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -1485,11 +1485,7 @@ uchar *QResourceFileEnginePrivate::map(qint64 offset, qint64 size, QFile::Memory { Q_Q(QResourceFileEngine); Q_UNUSED(flags); - if (!resource.isValid() - || offset < 0 - || size < 0 - || offset + size > resource.size() - || (size == 0)) { + if (offset < 0 || size <= 0 || !resource.isValid() || offset + size > resource.size()) { q->setError(QFile::UnspecifiedError, QString()); return 0; } |