diff options
157 files changed, 8321 insertions, 3045 deletions
@@ -119,6 +119,14 @@ translations/*.qm translations/*_untranslated.ts qrc_*.cpp +# Test generated files +QObject.log +tst_* +!tst_*.* +tst_*.log +tst_*.debug +tst_*~ + # xemacs temporary files *.flc @@ -203,7 +211,7 @@ doc-build # --------------------- ABLD.BAT -bld.inf +bld.inf* *.mmp *.mk *.rss @@ -221,6 +229,10 @@ plugin_commonu.def *.sym *.lib +# runonphone crash dumps +d_exc_*.txt +d_exc_*.stk + # Generated by abldfast.bat from devtools. .abldsteps.* diff --git a/demos/declarative/minehunt/minehunt.pro b/demos/declarative/minehunt/minehunt.pro index f591011..d23bb05 100644 --- a/demos/declarative/minehunt/minehunt.pro +++ b/demos/declarative/minehunt/minehunt.pro @@ -18,6 +18,6 @@ symbian:{ TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri) qmlminehuntfiles.files = MinehuntCore minehunt.qml - DEPLOYMENT = qmlminehuntfiles + DEPLOYMENT += qmlminehuntfiles } diff --git a/examples/declarative/cppextensions/imageprovider/imageprovider.pro b/examples/declarative/cppextensions/imageprovider/imageprovider.pro index f6e09a2..f700f0b 100644 --- a/examples/declarative/cppextensions/imageprovider/imageprovider.pro +++ b/examples/declarative/cppextensions/imageprovider/imageprovider.pro @@ -24,5 +24,5 @@ symbian:{ importFiles.files = ImageProviderCore/qmlimageproviderplugin.dll ImageProviderCore/qmldir importFiles.path = ImageProviderCore - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } diff --git a/examples/declarative/cppextensions/qwidgets/qwidgets.pro b/examples/declarative/cppextensions/qwidgets/qwidgets.pro index 0f5398b..d92e072 100644 --- a/examples/declarative/cppextensions/qwidgets/qwidgets.pro +++ b/examples/declarative/cppextensions/qwidgets/qwidgets.pro @@ -20,5 +20,5 @@ symbian:{ importFiles.files = QWidgets/qmlqwidgetsplugin.dll QWidgets/qmldir importFiles.path = QWidgets - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix index b9e281b..a24076e 100644 --- a/qmake/Makefile.unix +++ b/qmake/Makefile.unix @@ -16,10 +16,11 @@ OBJS=project.o property.o main.o makefile.o unixmake2.o unixmake.o \ #qt code QOBJS=qtextcodec.o qutfcodec.o qstring.o qtextstream.o qiodevice.o qmalloc.o qglobal.o \ qbytearray.o qbytearraymatcher.o qdatastream.o qbuffer.o qlist.o qfile.o \ - qfsfileengine_unix.o qfsfileengine_iterator_unix.o qfsfileengine.o \ + qfilesystementry.o qfilesystemengine_unix.o qfilesystemengine.o qfilesystemiterator_unix.o \ + qfsfileengine_unix.o qfsfileengine.o \ qfsfileengine_iterator.o qregexp.o qvector.o qbitarray.o qdir.o qdiriterator.o quuid.o qhash.o \ qfileinfo.o qdatetime.o qstringlist.o qabstractfileengine.o qtemporaryfile.o \ - qmap.o qmetatype.o qsettings.o qlibraryinfo.o qvariant.o qvsnprintf.o \ + qmap.o qmetatype.o qsettings.o qsystemerror.o qlibraryinfo.o qvariant.o qvsnprintf.o \ qlocale.o qlinkedlist.o qurl.o qnumeric.o qcryptographichash.o qxmlstream.o qxmlutils.o \ $(QTOBJS) @@ -44,8 +45,11 @@ DEPEND_SRC=project.cpp property.cpp meta.cpp main.cpp generators/makefile.cpp ge $(SOURCE_PATH)/src/corelib/global/qglobal.cpp $(SOURCE_PATH)/src/corelib/tools/qregexp.cpp \ $(SOURCE_PATH)/src/corelib/tools/qbytearray.cpp $(SOURCE_PATH)/src/corelib/tools/qbytearraymatcher.cpp \ $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp $(SOURCE_PATH)/src/corelib/io/qbuffer.cpp \ + $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_unix.cpp \ + $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_mac.cpp \ + $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_unix.cpp \ $(SOURCE_PATH)/src/corelib/io/qfsfileengine_unix.cpp $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp \ - $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator_unix.cpp $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.cpp \ + $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.cpp \ $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp $(SOURCE_PATH)/src/corelib/tools/qlist.cpp \ $(SOURCE_PATH)/src/corelib/tools/qvector.cpp $(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp \ $(SOURCE_PATH)/src/corelib/io/qdiriterator.cpp \ @@ -61,6 +65,7 @@ DEPEND_SRC=project.cpp property.cpp meta.cpp main.cpp generators/makefile.cpp ge $(SOURCE_PATH)/src/corelib/tools/qvsnprintf.cpp $(SOURCE_PATH)/src/corelib/global/qnumeric.cpp \ $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp \ $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp \ + $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp \ $(QTSRCS) CPPFLAGS = -I. -Igenerators -Igenerators/unix -Igenerators/win32 -Igenerators/mac -Igenerators/symbian \ @@ -100,6 +105,9 @@ qvariant.o: $(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp qsettings.o: $(SOURCE_PATH)/src/corelib/io/qsettings.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qsettings.cpp +qsystemerror.o: $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp + qlibraryinfo.o: $(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp @@ -160,6 +168,21 @@ qlist.o: $(SOURCE_PATH)/src/corelib/tools/qlist.cpp qfile.o: $(SOURCE_PATH)/src/corelib/io/qfile.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfile.cpp +qfilesystementry.o: $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp + +qfilesystemengine.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp + +qfilesystemengine_unix.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_unix.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_unix.cpp + +qfilesystemengine_mac.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_mac.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_mac.cpp + +qfilesystemiterator_unix.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_unix.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_unix.cpp + qfsfileengine.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp @@ -169,9 +192,6 @@ qfsfileengine_iterator.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.c qfsfileengine_unix.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_unix.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_unix.cpp -qfsfileengine_iterator_unix.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator_unix.cpp - $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator_unix.cpp - qabstractfileengine.o: $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32 index c04bcb2..4d29537 100644 --- a/qmake/Makefile.win32 +++ b/qmake/Makefile.win32 @@ -73,6 +73,10 @@ QTOBJS= \ qbitarray.obj \ qbuffer.obj \ qcryptographichash.obj \ + qfilesystementry.obj \ + qfilesystemengine.obj \ + qfilesystemengine_win.obj \ + qfilesystemiterator_win.obj \ qfsfileengine.obj \ qfsfileengine_iterator.obj \ qbytearray.obj \ @@ -86,7 +90,6 @@ QTOBJS= \ qabstractfileengine.obj \ qfsfileengine_win.obj \ qsystemlibrary.obj \ - qfsfileengine_iterator_win.obj \ qfileinfo.obj \ qglobal.obj \ qhash.obj \ @@ -101,6 +104,7 @@ QTOBJS= \ qutfcodec.obj \ qstring.obj \ qstringlist.obj \ + qsystemerror.obj \ qtextstream.obj \ qdatastream.obj \ quuid.obj \ diff --git a/qmake/Makefile.win32-g++ b/qmake/Makefile.win32-g++ index 29fbd0a..59ac8c2 100644 --- a/qmake/Makefile.win32-g++ +++ b/qmake/Makefile.win32-g++ @@ -61,10 +61,13 @@ QTOBJS= \ qtemporaryfile.o \ qfileinfo.o \ qabstractfileengine.o \ + qfilesystementry.o \ + qfilesystemengine.o \ + qfilesystemengine_win.o \ + qfilesystemiterator_win.o \ qfsfileengine.o \ qfsfileengine_iterator.o \ qfsfileengine_win.o \ - qfsfileengine_iterator_win.o \ qglobal.o \ qhash.o \ qiodevice.o \ @@ -79,6 +82,7 @@ QTOBJS= \ qutfcodec.o \ qstring.o \ qstringlist.o \ + qsystemerror.o \ qsystemlibrary.o \ qtextstream.o \ quuid.o \ @@ -193,12 +197,21 @@ qtemporaryfile.o: $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp qabstractfileengine.o: $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp +qfilesystementry.o: $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp + +qfilesystemengine.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp + +qfilesystemengine_win.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_win.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_win.cpp + +qfilesystemiterator_win.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_win.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_win.cpp + qfsfileengine_win.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_win.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_win.cpp -qfsfileengine_iterator_win.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator_win.cpp - $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator_win.cpp - qfsfileengine.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp @@ -235,6 +248,9 @@ qdatetime.o: $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp qstringlist.o: $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp +qsystemerror.o: $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp + qsystemlibrary.o: $(SOURCE_PATH)/src/corelib/plugin/qsystemlibrary.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/plugin/qsystemlibrary.cpp diff --git a/qmake/Makefile.win32-g++-sh b/qmake/Makefile.win32-g++-sh index 9c7942c..a84b3f6 100644 --- a/qmake/Makefile.win32-g++-sh +++ b/qmake/Makefile.win32-g++-sh @@ -61,10 +61,13 @@ QTOBJS= \ qtemporaryfile.o \ qfileinfo.o \ qabstractfileengine.o \ + qfilesystementry.o \ + qfilesystemengine.o \ + qfilesystemengine_win.o \ + qfilesystemiterator_win.o \ qfsfileengine.o \ qfsfileengine_iterator.o \ qfsfileengine_win.o \ - qfsfileengine_iterator_win.o \ qglobal.o \ qhash.o \ qiodevice.o \ @@ -80,6 +83,7 @@ QTOBJS= \ qstring.o \ qstringlist.o \ qsystemlibrary.o \ + qsystemerror.o \ qtextstream.o \ quuid.o \ qvector.o \ @@ -192,12 +196,21 @@ qtemporaryfile.o: $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp qabstractfileengine.o: $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp +qfilesystementry.o: $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp + +qfilesystemengine.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp + +qfilesystemengine_win.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_win.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_win.cpp + +qfilesystemiterator_win.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_win.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_win.cpp + qfsfileengine_win.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_win.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_win.cpp -qfsfileengine_iterator_win.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator_win.cpp - $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator_win.cpp - qfsfileengine.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp @@ -234,6 +247,9 @@ qdatetime.o: $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp qstringlist.o: $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp +qsystemerror.o: $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp + qsystemlibrary.o: $(SOURCE_PATH)/src/corelib/plugin/qsystemlibrary.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/plugin/qsystemlibrary.cpp diff --git a/qmake/qmake.pri b/qmake/qmake.pri index 8f46a2e..bc7ddb8 100644 --- a/qmake/qmake.pri +++ b/qmake/qmake.pri @@ -57,6 +57,8 @@ bootstrap { #Qt code qfile.cpp \ qabstractfileengine.cpp \ qfileinfo.cpp \ + qfilesystementry.cpp \ + qfilesystemengine.cpp \ qfsfileengine.cpp \ qfsfileengine_iterator.cpp \ qglobal.cpp \ @@ -80,6 +82,7 @@ bootstrap { #Qt code quuid.cpp \ qsettings.cpp \ qlibraryinfo.cpp \ + qsystemerror.cpp \ qvariant.cpp \ qvector.cpp \ qvsnprintf.cpp \ @@ -96,6 +99,7 @@ bootstrap { #Qt code qdatetime.h \ qdatetime_p.h \ qdir.h \ + qdir_p.h \ qdiriterator.h \ qfile.h \ qabstractfileengine.h \ @@ -116,6 +120,7 @@ bootstrap { #Qt code qstring.h \ qstringlist.h \ qstringmatcher.h \ + qsystemerror_p.h \ qtemporaryfile.h \ qtextstream.h \ qurl.h \ @@ -125,14 +130,15 @@ bootstrap { #Qt code qxmlutils.h unix { - SOURCES += qfsfileengine_unix.cpp qfsfileengine_iterator_unix.cpp + SOURCES += qfilesystemengine_unix.cpp qfilesystemiterator_unix.cpp qfsfileengine_unix.cpp mac { + SOURCES += qfilesystemengine_mac.cpp SOURCES += qcore_mac.cpp qsettings_mac.cpp QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 #enables weak linking for 10.4 (exported) LIBS += -framework ApplicationServices } } else:win32 { - SOURCES += qfsfileengine_win.cpp qfsfileengine_iterator_win.cpp qsettings_win.cpp \ + SOURCES += qfilesystemengine_win.cpp qfsfileengine_win.cpp qfilesystemiterator_win.cpp qsettings_win.cpp \ qsystemlibrary.cpp win32-msvc*:LIBS += ole32.lib advapi32.lib win32-g++*:LIBS += -lole32 -luuid diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index cfb40bc..4d4ae21 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -9,6 +9,7 @@ HEADERS += \ io/qdataurl_p.h \ io/qdebug.h \ io/qdir.h \ + io/qdir_p.h \ io/qdiriterator.h \ io/qfile.h \ io/qfileinfo.h \ @@ -29,7 +30,11 @@ HEADERS += \ io/qfsfileengine_p.h \ io/qfsfileengine_iterator_p.h \ io/qfilesystemwatcher.h \ - io/qfilesystemwatcher_p.h + io/qfilesystemwatcher_p.h \ + io/qfilesystementry_p.h \ + io/qfilesystemengine_p.h \ + io/qfilesystemmetadata_p.h \ + io/qfilesystemiterator_p.h SOURCES += \ io/qabstractfileengine.cpp \ @@ -52,25 +57,35 @@ SOURCES += \ io/qsettings.cpp \ io/qfsfileengine.cpp \ io/qfsfileengine_iterator.cpp \ - io/qfilesystemwatcher.cpp + io/qfilesystemwatcher.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/qfsfileengine_iterator_win.cpp SOURCES += io/qfilesystemwatcher_win.cpp HEADERS += io/qfilesystemwatcher_win_p.h HEADERS += io/qwindowspipewriter_p.h SOURCES += io/qwindowspipewriter.cpp + SOURCES += io/qfilesystemengine_win.cpp + SOURCES += io/qfilesystemiterator_win.cpp } else:unix { SOURCES += io/qfsfileengine_unix.cpp - SOURCES += io/qfsfileengine_iterator_unix.cpp - symbian:SOURCES += io/qprocess_symbian.cpp - else:SOURCES += io/qprocess_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 + } !nacl:macx-*: { HEADERS += io/qfilesystemwatcher_fsevents_p.h + SOURCES += io/qfilesystemengine_mac.cpp SOURCES += io/qsettings_mac.cpp io/qfilesystemwatcher_fsevents.cpp } diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 37a093c..67109aa 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -52,6 +52,10 @@ #include "qdiriterator.h" #include "qstringbuilder.h" +#include <QtCore/private/qfilesystementry_p.h> +#include <QtCore/private/qfilesystemmetadata_p.h> +#include <QtCore/private/qfilesystemengine_p.h> + QT_BEGIN_NAMESPACE /*! @@ -149,6 +153,29 @@ QAbstractFileEngineHandler::~QAbstractFileEngineHandler() } } +/* + \ìnternal + + Handles calls to custom file engine handlers. +*/ +QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path) +{ + QAbstractFileEngine *engine = 0; + + if (qt_file_engine_handlers_in_use) { + QReadLocker locker(fileEngineHandlerMutex()); + + // check for registered handlers that can load the file + QAbstractFileEngineHandlerList *handlers = fileEngineHandlers(); + for (int i = 0; i < handlers->size(); i++) { + if ((engine = handlers->at(i)->create(path))) + break; + } + } + + return engine; +} + /*! \fn QAbstractFileEngine *QAbstractFileEngineHandler::create(const QString &fileName) const @@ -177,57 +204,17 @@ QAbstractFileEngineHandler::~QAbstractFileEngineHandler() */ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName) { - if (qt_file_engine_handlers_in_use) { - QReadLocker locker(fileEngineHandlerMutex()); - - // check for registered handlers that can load the file - QAbstractFileEngineHandlerList *handlers = fileEngineHandlers(); - for (int i = 0; i < handlers->size(); i++) { - if (QAbstractFileEngine *ret = handlers->at(i)->create(fileName)) - return ret; - } - } - -#ifdef QT_BUILD_CORE_LIB - for (int prefixSeparator = 0; prefixSeparator < fileName.size(); ++prefixSeparator) { - QChar const ch = fileName[prefixSeparator]; - if (ch == QLatin1Char('/')) - break; - - if (ch == QLatin1Char(':')) { - if (prefixSeparator == 0) - return new QResourceFileEngine(fileName); - - if (prefixSeparator == 1) - break; - - const QStringList &paths = QDir::searchPaths(fileName.left(prefixSeparator)); - for (int i = 0; i < paths.count(); i++) { - QAbstractFileEngine *engine = create(paths.at(i) % QLatin1Char('/') % fileName.mid(prefixSeparator + 1)); - if (engine && (engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) { - return engine; - } - delete engine; - } - - break; - } - - // There's no need to fully validate the prefix here. Consulting the - // unicode tables could be expensive and validation is already - // performed in QDir::setSearchPaths. - // - // if (!ch.isLetterOrNumber()) - // break; - } + QFileSystemEntry entry(fileName); + QFileSystemMetaData metaData; + QAbstractFileEngine *engine = QFileSystemEngine::resolveEntryAndCreateLegacyEngine(entry, metaData); + +#ifndef QT_NO_FSFILEENGINE + if (!engine) + // fall back to regular file engine + return new QFSFileEngine(entry.filePath()); #endif -#ifdef QT_NO_FSFILEENGINE - return 0; -#else - // fall back to regular file engine - return new QFSFileEngine(fileName); -#endif + return engine; } /*! diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h index e1eba30..075ec81 100644 --- a/src/corelib/io/qabstractfileengine_p.h +++ b/src/corelib/io/qabstractfileengine_p.h @@ -74,6 +74,8 @@ public: Q_DECLARE_PUBLIC(QAbstractFileEngine) }; +QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path); + QT_END_NAMESPACE #endif // QABSTRACTFILEENGINE_P_H diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 426f61e..2f97c3a 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -41,6 +41,7 @@ #include "qplatformdefs.h" #include "qdir.h" +#include "qdir_p.h" #include "qabstractfileengine.h" #ifndef QT_NO_DEBUG_STREAM #include "qdebug.h" @@ -53,6 +54,10 @@ #include "qvector.h" #include "qalgorithms.h" #include "qvarlengtharray.h" +#include "qfilesystementry_p.h" +#include "qfilesystemmetadata_p.h" +#include "qfilesystemengine_p.h" +#include <qstringbuilder.h> #ifdef QT_BUILD_CORE_LIB # include "qresource.h" @@ -81,129 +86,123 @@ static QString driveSpec(const QString &path) } //************* QDirPrivate -class QDirPrivate - : public QSharedData -{ -public: - QDirPrivate(const QString &path, - const QStringList &nameFilters_ = QStringList(), - QDir::SortFlags sort_ = QDir::SortFlags(QDir::Name | QDir::IgnoreCase), - QDir::Filters filters_ = QDir::AllEntries) - : QSharedData() - , nameFilters(nameFilters_) - , sort(sort_) - , filters(filters_) +QDirPrivate::QDirPrivate(const QString &path, const QStringList &nameFilters_, QDir::SortFlags sort_, QDir::Filters filters_) + : QSharedData() + , nameFilters(nameFilters_) + , sort(sort_) + , filters(filters_) #ifdef QT3_SUPPORT - , filterSepChar(0) - , matchAllDirs(false) + , filterSepChar(0) + , matchAllDirs(false) #endif - , fileListsInitialized(false) - { - setPath(path.isEmpty() ? QString::fromLatin1(".") : path); - - bool empty = nameFilters.isEmpty(); - if (!empty) { - empty = true; - for (int i = 0; i < nameFilters.size(); ++i) { - if (!nameFilters.at(i).isEmpty()) { - empty = false; - break; - } + , fileListsInitialized(false) +{ + setPath(path.isEmpty() ? QString::fromLatin1(".") : path); + + bool empty = nameFilters.isEmpty(); + if (!empty) { + empty = true; + for (int i = 0; i < nameFilters.size(); ++i) { + if (!nameFilters.at(i).isEmpty()) { + empty = false; + break; } } - if (empty) - nameFilters = QStringList(QString::fromLatin1("*")); } + if (empty) + nameFilters = QStringList(QString::fromLatin1("*")); +} - QDirPrivate(const QDirPrivate ©) - : QSharedData(copy) - , path(copy.path) - , nameFilters(copy.nameFilters) - , sort(copy.sort) - , filters(copy.filters) +QDirPrivate::QDirPrivate(const QDirPrivate ©) + : QSharedData(copy) + , nameFilters(copy.nameFilters) + , sort(copy.sort) + , filters(copy.filters) #ifdef QT3_SUPPORT - , filterSepChar(copy.filterSepChar) - , matchAllDirs(copy.matchAllDirs) + , filterSepChar(copy.filterSepChar) + , matchAllDirs(copy.matchAllDirs) #endif - , fileListsInitialized(false) - { - } + , fileListsInitialized(false) + , dirEntry(copy.dirEntry) + , metaData(copy.metaData) +{ +} - bool exists() const - { - const QAbstractFileEngine::FileFlags info = - fileEngine->fileFlags(QAbstractFileEngine::DirectoryType - | QAbstractFileEngine::ExistsFlag - | QAbstractFileEngine::Refresh); - if (!(info & QAbstractFileEngine::DirectoryType)) - return false; - return info & QAbstractFileEngine::ExistsFlag; +bool QDirPrivate::exists() const +{ + if (fileEngine.isNull()) { + QFileSystemEngine::fillMetaData(dirEntry, metaData, + QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType); // always stat + return metaData.exists() && metaData.isDirectory(); } + const QAbstractFileEngine::FileFlags info = + fileEngine->fileFlags(QAbstractFileEngine::DirectoryType + | QAbstractFileEngine::ExistsFlag + | QAbstractFileEngine::Refresh); + if (!(info & QAbstractFileEngine::DirectoryType)) + return false; + return info & QAbstractFileEngine::ExistsFlag; +} - void initFileEngine(); - void initFileLists() const; - - static void sortFileList(QDir::SortFlags, QFileInfoList &, QStringList *, QFileInfoList *); - - static inline QChar getFilterSepChar(const QString &nameFilter) - { - QChar sep(QLatin1Char(';')); - int i = nameFilter.indexOf(sep, 0); - if (i == -1 && nameFilter.indexOf(QLatin1Char(' '), 0) != -1) - sep = QChar(QLatin1Char(' ')); - return sep; - } +// static +inline QChar QDirPrivate::getFilterSepChar(const QString &nameFilter) +{ + QChar sep(QLatin1Char(';')); + int i = nameFilter.indexOf(sep, 0); + if (i == -1 && nameFilter.indexOf(QLatin1Char(' '), 0) != -1) + sep = QChar(QLatin1Char(' ')); + return sep; +} - static inline QStringList splitFilters(const QString &nameFilter, QChar sep = 0) - { - if (sep == 0) - sep = getFilterSepChar(nameFilter); - QStringList ret = nameFilter.split(sep); - for (int i = 0; i < ret.count(); ++i) - ret[i] = ret[i].trimmed(); - return ret; - } +// static +inline QStringList QDirPrivate::splitFilters(const QString &nameFilter, QChar sep) +{ + if (sep == 0) + sep = getFilterSepChar(nameFilter); + QStringList ret = nameFilter.split(sep); + for (int i = 0; i < ret.count(); ++i) + ret[i] = ret[i].trimmed(); + return ret; +} - inline void setPath(QString p) - { - if ((p.endsWith(QLatin1Char('/')) || p.endsWith(QLatin1Char('\\'))) - && p.length() > 1) { +inline void QDirPrivate::setPath(const QString &path) +{ + QString p = QDir::fromNativeSeparators(path); + if (p.endsWith(QLatin1Char('/')) + && p.length() > 1 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) - if (!(p.length() == 3 && p.at(1) == QLatin1Char(':'))) + && (!(p.length() == 3 && p.at(1).unicode() == ':' && p.at(0).isLetter())) #endif - p.truncate(p.length() - 1); - } - - path = p; - initFileEngine(); - - // set the path to be the qt friendly version so then we can operate on it using just / - path = fileEngine->fileName(QAbstractFileEngine::DefaultName); - clearFileLists(); + ) { + p.truncate(p.length() - 1); } - inline void clearFileLists() { - fileListsInitialized = false; - files.clear(); - fileInfos.clear(); - } - - QString path; - QStringList nameFilters; - QDir::SortFlags sort; - QDir::Filters filters; + dirEntry = QFileSystemEntry(p, QFileSystemEntry::FromInternalPath()); + metaData.clear(); + initFileEngine(); + clearFileLists(); + absoluteDirEntry = QFileSystemEntry(); +} -#ifdef QT3_SUPPORT - QChar filterSepChar; - bool matchAllDirs; -#endif +inline void QDirPrivate::clearFileLists() +{ + fileListsInitialized = false; + files.clear(); + fileInfos.clear(); +} - QScopedPointer<QAbstractFileEngine> fileEngine; +inline void QDirPrivate::resolveAbsoluteEntry() const +{ + if (!absoluteDirEntry.isEmpty() || dirEntry.isEmpty()) + return; - mutable bool fileListsInitialized; - mutable QStringList files; - mutable QFileInfoList fileInfos; -}; + if (dirEntry.isRelative()) { + QFileSystemEntry answer = QFileSystemEngine::absoluteName(dirEntry); + absoluteDirEntry = QFileSystemEntry(QDir::cleanPath(answer.filePath()), QFileSystemEntry::FromInternalPath()); + } else { + absoluteDirEntry = dirEntry; + } +} /* For sorting */ struct QDirSortItem @@ -315,12 +314,11 @@ inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QFileInfoList &l, } } } - -inline void QDirPrivate::initFileLists() const +inline void QDirPrivate::initFileLists(const QDir &dir) const { if (!fileListsInitialized) { QFileInfoList l; - QDirIterator it(path, nameFilters, filters); + QDirIterator it(dir); while (it.hasNext()) { it.next(); l.append(it.fileInfo()); @@ -332,7 +330,7 @@ inline void QDirPrivate::initFileLists() const inline void QDirPrivate::initFileEngine() { - fileEngine.reset(QAbstractFileEngine::create(path)); + fileEngine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData)); } /*! @@ -597,7 +595,7 @@ void QDir::setPath(const QString &path) QString QDir::path() const { const QDirPrivate* d = d_ptr.constData(); - return d->path; + return d->dirEntry.filePath(); } /*! @@ -611,10 +609,8 @@ QString QDir::path() const QString QDir::absolutePath() const { const QDirPrivate* d = d_ptr.constData(); - QString ret = d->path; - if (QDir::isRelativePath(ret)) - ret = absoluteFilePath(QString::fromLatin1("")); - return cleanPath(ret); + d->resolveAbsoluteEntry(); + return d->absoluteDirEntry.filePath(); } /*! @@ -635,7 +631,12 @@ QString QDir::absolutePath() const */ QString QDir::canonicalPath() const { - return cleanPath(d_ptr->fileEngine->fileName(QAbstractFileEngine::CanonicalName)); + const QDirPrivate* d = d_ptr.constData(); + if (d->fileEngine.isNull()) { + QFileSystemEntry answer = QFileSystemEngine::canonicalName(d->dirEntry, d->metaData); + return answer.filePath(); + } + return d->fileEngine->fileName(QAbstractFileEngine::CanonicalName); } /*! @@ -652,10 +653,7 @@ QString QDir::canonicalPath() const QString QDir::dirName() const { const QDirPrivate* d = d_ptr.constData(); - int pos = d->path.lastIndexOf(QLatin1Char('/')); - if (pos == -1) - return d->path; - return d->path.mid(pos + 1); + return d->dirEntry.fileName(); } /*! @@ -673,7 +671,7 @@ QString QDir::filePath(const QString &fileName) const if (isAbsolutePath(fileName)) return QString(fileName); - QString ret = d->path; + QString ret = d->dirEntry.filePath(); if (!fileName.isEmpty()) { if (!ret.isEmpty() && ret[(int)ret.length()-1] != QLatin1Char('/') && fileName[0] != QLatin1Char('/')) ret += QLatin1Char('/'); @@ -696,22 +694,12 @@ QString QDir::absoluteFilePath(const QString &fileName) const if (isAbsolutePath(fileName)) return fileName; - QString ret; -#ifndef QT_NO_FSFILEENGINE - if (isRelativePath(d->path)) //get pwd - ret = QFSFileEngine::currentPath(fileName); -#endif - if (!d->path.isEmpty() && d->path != QLatin1String(".")) { - if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/'))) - ret += QLatin1Char('/'); - ret += d->path; - } - if (!fileName.isEmpty()) { - if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/'))) - ret += QLatin1Char('/'); - ret += fileName; - } - return ret; + d->resolveAbsoluteEntry(); + if (fileName.isEmpty()) + return d->absoluteDirEntry.filePath(); + if (!d->absoluteDirEntry.isRoot()) + return d->absoluteDirEntry.filePath() % QLatin1Char('/') % fileName; + return d->absoluteDirEntry.filePath() % fileName; } /*! @@ -723,7 +711,7 @@ QString QDir::absoluteFilePath(const QString &fileName) const */ QString QDir::relativeFilePath(const QString &fileName) const { - QString dir = absolutePath(); + QString dir = cleanPath(absolutePath()); QString file = cleanPath(fileName); if (isRelativePath(file) || isRelativePath(dir)) @@ -859,21 +847,22 @@ bool QDir::cd(const QString &dirName) if (dirName.isEmpty() || dirName == QLatin1String(".")) return true; - QString newPath = d->path; + QString newPath; if (isAbsolutePath(dirName)) { newPath = cleanPath(dirName); } else { if (isRoot()) { if (dirName == QLatin1String("..")) return false; + newPath = d->dirEntry.filePath(); } else { - newPath += QLatin1Char('/'); + newPath = d->dirEntry.filePath() % QLatin1Char('/'); } newPath += dirName; if (dirName.indexOf(QLatin1Char('/')) >= 0 - || d->path == QLatin1String(".") - || dirName == QLatin1String("..")) { + || dirName == QLatin1String("..") + || d->dirEntry.filePath() == QLatin1String(".")) { newPath = cleanPath(newPath); /* If newPath starts with .., we convert it to absolute to @@ -891,7 +880,6 @@ bool QDir::cd(const QString &dirName) QScopedPointer<QDirPrivate> dir(new QDirPrivate(*d_ptr.constData())); dir->setPath(newPath); - if (!dir->exists()) return false; @@ -1204,7 +1192,7 @@ void QDir::setSorting(SortFlags sort) uint QDir::count() const { const QDirPrivate* d = d_ptr.constData(); - d->initFileLists(); + d->initFileLists(*this); return d->files.count(); } @@ -1218,7 +1206,7 @@ uint QDir::count() const QString QDir::operator[](int pos) const { const QDirPrivate* d = d_ptr.constData(); - d->initFileLists(); + d->initFileLists(*this); return d->files[pos]; } @@ -1301,12 +1289,12 @@ QStringList QDir::entryList(const QStringList &nameFilters, Filters filters, sort = d->sort; if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) { - d->initFileLists(); + d->initFileLists(*this); return d->files; } QFileInfoList l; - QDirIterator it(d->path, nameFilters, filters); + QDirIterator it(d->dirEntry.filePath(), nameFilters, filters); while (it.hasNext()) { it.next(); l.append(it.fileInfo()); @@ -1347,12 +1335,12 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter sort = d->sort; if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) { - d->initFileLists(); + d->initFileLists(*this); return d->fileInfos; } QFileInfoList l; - QDirIterator it(d->path, nameFilters, filters); + QDirIterator it(d->dirEntry.filePath(), nameFilters, filters); while (it.hasNext()) { it.next(); l.append(it.fileInfo()); @@ -1367,8 +1355,11 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter Returns true on success; otherwise returns false. + If the directory already exists when this function is called, it will return false. + \sa rmdir() */ +// ### Qt5: behaviour when directory already exists should be made consistent for mkdir and mkpath bool QDir::mkdir(const QString &dirName) const { const QDirPrivate* d = d_ptr.constData(); @@ -1379,6 +1370,8 @@ bool QDir::mkdir(const QString &dirName) const } QString fn = filePath(dirName); + if (d->fileEngine.isNull()) + return QFileSystemEngine::createDirectory(QFileSystemEntry(fn), false); return d->fileEngine->mkdir(fn, false); } @@ -1401,6 +1394,9 @@ bool QDir::rmdir(const QString &dirName) const } QString fn = filePath(dirName); + if (d->fileEngine.isNull()) + return QFileSystemEngine::removeDirectory(QFileSystemEntry(fn), false); + return d->fileEngine->rmdir(fn, false); } @@ -1412,8 +1408,11 @@ bool QDir::rmdir(const QString &dirName) const Returns true if successful; otherwise returns false. + If the path already exists when this function is called, it will return true. + \sa rmpath() */ +// ### Qt5: behaviour when directory already exists should be made consistent for mkdir and mkpath bool QDir::mkpath(const QString &dirPath) const { const QDirPrivate* d = d_ptr.constData(); @@ -1424,6 +1423,8 @@ bool QDir::mkpath(const QString &dirPath) const } QString fn = filePath(dirPath); + if (d->fileEngine.isNull()) + return QFileSystemEngine::createDirectory(QFileSystemEntry(fn), true); return d->fileEngine->mkdir(fn, true); } @@ -1448,6 +1449,8 @@ bool QDir::rmpath(const QString &dirPath) const } QString fn = filePath(dirPath); + if (d->fileEngine.isNull()) + return QFileSystemEngine::removeDirectory(QFileSystemEntry(fn), true); return d->fileEngine->rmdir(fn, true); } @@ -1464,6 +1467,13 @@ bool QDir::isReadable() const { const QDirPrivate* d = d_ptr.constData(); + if (d->fileEngine.isNull()) { + if (!d->metaData.hasFlags(QFileSystemMetaData::UserReadPermission)) + QFileSystemEngine::fillMetaData(d->dirEntry, d->metaData, QFileSystemMetaData::UserReadPermission); + + return (d->metaData.permissions() & QFile::ReadUser) != 0; + } + const QAbstractFileEngine::FileFlags info = d->fileEngine->fileFlags(QAbstractFileEngine::DirectoryType | QAbstractFileEngine::PermsMask); @@ -1502,6 +1512,8 @@ bool QDir::exists() const */ bool QDir::isRoot() const { + if (d_ptr->fileEngine.isNull()) + return d_ptr->dirEntry.isRoot(); return d_ptr->fileEngine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::RootFlag; } @@ -1532,6 +1544,8 @@ bool QDir::isRoot() const */ bool QDir::isRelative() const { + if (d_ptr->fileEngine.isNull()) + return d_ptr->dirEntry.isRelative(); return d_ptr->fileEngine->isRelativePath(); } @@ -1543,20 +1557,23 @@ bool QDir::isRelative() const \sa isAbsolute() isAbsolutePath() isRelative() cleanPath() */ -bool QDir::makeAbsolute() // ### What do the return values signify? +bool QDir::makeAbsolute() { - QString absolutePath = d_ptr.constData()->fileEngine->fileName(QAbstractFileEngine::AbsoluteName); - if (QDir::isRelativePath(absolutePath)) - return false; - - QScopedPointer<QDirPrivate> dir(new QDirPrivate(*d_ptr.constData())); - dir->setPath(absolutePath); - - d_ptr = dir.take(); - - if (!(d_ptr->fileEngine->fileFlags(QAbstractFileEngine::TypesMask) & QAbstractFileEngine::DirectoryType)) - return false; + const QDirPrivate *d = d_ptr.constData(); + QScopedPointer<QDirPrivate> dir; + if (!d->fileEngine.isNull()) { + QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName); + if (QDir::isRelativePath(absolutePath)) + return false; + dir.reset(new QDirPrivate(*d_ptr.constData())); + dir->setPath(absolutePath); + } else { // native FS + d->resolveAbsoluteEntry(); + dir.reset(new QDirPrivate(*d_ptr.constData())); + dir->setPath(d->absoluteDirEntry.filePath()); + } + d_ptr = dir.take(); // actually detach return true; } @@ -1576,17 +1593,24 @@ bool QDir::operator==(const QDir &dir) const if (d == other) return true; - if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive()) - return false; + Qt::CaseSensitivity sensitive; + if (d->fileEngine.isNull() || other->fileEngine.isNull()) { + if (d->fileEngine.data() != other->fileEngine.data()) // one is native, the other is a custom file-engine + return false; + + sensitive = QFileSystemEngine::isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive; + } else { + if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive()) + return false; + sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive; + } + if (d->filters == other->filters && d->sort == other->sort && d->nameFilters == other->nameFilters) { - QString dir1 = absolutePath(), dir2 = dir.absolutePath(); - if (!other->fileEngine->caseSensitive()) - return (dir1.toLower() == dir2.toLower()); - - return (dir1 == dir2); - + d->resolveAbsoluteEntry(); + other->resolveAbsoluteEntry(); + return d->absoluteDirEntry.filePath().compare(other->absoluteDirEntry.filePath(), sensitive) == 0; } return false; } @@ -1735,12 +1759,7 @@ QChar QDir::separator() */ bool QDir::setCurrent(const QString &path) { -#ifdef QT_NO_FSFILEENGINE - Q_UNUSED(path); - return false; -#else - return QFSFileEngine::setCurrentPath(path); -#endif + return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path)); } /*! @@ -1761,11 +1780,7 @@ bool QDir::setCurrent(const QString &path) */ QString QDir::currentPath() { -#ifdef QT_NO_FSFILEENGINE - return QString(); -#else - return QFSFileEngine::currentPath(); -#endif + return QFileSystemEngine::currentPath().filePath(); } /*! @@ -1823,11 +1838,7 @@ QString QDir::currentPath() */ QString QDir::homePath() { -#ifdef QT_NO_FSFILEENGINE - return QString(); -#else - return cleanPath(QFSFileEngine::homePath()); -#endif + return QFileSystemEngine::homePath(); } /*! @@ -1866,11 +1877,7 @@ QString QDir::homePath() */ QString QDir::tempPath() { -#ifdef QT_NO_FSFILEENGINE - return QString(); -#else - return cleanPath(QFSFileEngine::tempPath()); -#endif + return QFileSystemEngine::tempPath(); } /*! @@ -1897,11 +1904,7 @@ QString QDir::tempPath() */ QString QDir::rootPath() { -#ifdef QT_NO_FSFILEENGINE - return QString(); -#else - return QFSFileEngine::rootPath(); -#endif + return QFileSystemEngine::rootPath(); } /*! @@ -2098,6 +2101,7 @@ bool QDir::isRelativePath(const QString &path) void QDir::refresh() const { QDirPrivate *d = const_cast<QDir*>(this)->d_ptr.data(); + d->metaData.clear(); d->initFileEngine(); d->clearFileLists(); } diff --git a/src/corelib/io/qdir_p.h b/src/corelib/io/qdir_p.h new file mode 100644 index 0000000..5f97c1f --- /dev/null +++ b/src/corelib/io/qdir_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIR_PRIVATE_H +#define QDIR_PRIVATE_H + +#include "qfilesystementry_p.h" +#include "qfilesystemmetadata_p.h" + +QT_BEGIN_NAMESPACE + +class QDirPrivate : public QSharedData +{ +public: + QDirPrivate(const QString &path, const QStringList &nameFilters_ = QStringList(), + QDir::SortFlags sort_ = QDir::SortFlags(QDir::Name | QDir::IgnoreCase), + QDir::Filters filters_ = QDir::AllEntries); + + QDirPrivate(const QDirPrivate ©); + + bool exists() const; + + void initFileEngine(); + void initFileLists(const QDir &dir) const; + + static void sortFileList(QDir::SortFlags, QFileInfoList &, QStringList *, QFileInfoList *); + + static inline QChar getFilterSepChar(const QString &nameFilter); + + static inline QStringList splitFilters(const QString &nameFilter, QChar sep = 0); + + inline void setPath(const QString &path); + + inline void clearFileLists(); + + inline void resolveAbsoluteEntry() const; + + QStringList nameFilters; + QDir::SortFlags sort; + QDir::Filters filters; + +#ifdef QT3_SUPPORT + QChar filterSepChar; + bool matchAllDirs; +#endif + + QScopedPointer<QAbstractFileEngine> fileEngine; + + mutable bool fileListsInitialized; + mutable QStringList files; + mutable QFileInfoList fileInfos; + + QFileSystemEntry dirEntry; + mutable QFileSystemEntry absoluteDirEntry; + mutable QFileSystemMetaData metaData; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index fd4b9c1..a8192ea 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -90,6 +90,7 @@ */ #include "qdiriterator.h" +#include "qdir_p.h" #include "qabstractfileengine.h" @@ -97,36 +98,41 @@ #include <QtCore/qstack.h> #include <QtCore/qvariant.h> +#include <QtCore/private/qfilesystemiterator_p.h> +#include <QtCore/private/qfilesystementry_p.h> +#include <QtCore/private/qfilesystemmetadata_p.h> +#include <QtCore/private/qfilesystemengine_p.h> +#include <QtCore/qfsfileengine.h> +#include <QtCore/private/qfileinfo_p.h> + QT_BEGIN_NAMESPACE -class QDirIteratorPrivateIteratorStack : public QStack<QAbstractFileEngineIterator *> +template <class Iterator> +class QDirIteratorPrivateIteratorStack : public QStack<Iterator *> { public: - ~QDirIteratorPrivateIteratorStack(); + ~QDirIteratorPrivateIteratorStack() + { + qDeleteAll(*this); + } }; -QDirIteratorPrivateIteratorStack::~QDirIteratorPrivateIteratorStack() -{ - qDeleteAll(*this); -} - - class QDirIteratorPrivate { public: - QDirIteratorPrivate(const QString &path, const QStringList &nameFilters, - QDir::Filters filters, QDirIterator::IteratorFlags flags); - ~QDirIteratorPrivate(); + QDirIteratorPrivate(const QFileSystemEntry &entry, const QStringList &nameFilters, + QDir::Filters filters, QDirIterator::IteratorFlags flags, bool resolveEngine = true); void advance(); + bool entryMatches(const QString & fileName, const QFileInfo &fileInfo); void pushDirectory(const QFileInfo &fileInfo); void checkAndPushDirectory(const QFileInfo &); bool matchesFilters(const QString &fileName, const QFileInfo &fi) const; QScopedPointer<QAbstractFileEngine> engine; - const QString path; + QFileSystemEntry dirEntry; const QStringList nameFilters; const QDir::Filters filters; const QDirIterator::IteratorFlags iteratorFlags; @@ -135,23 +141,22 @@ public: QVector<QRegExp> nameRegExps; #endif - QDirIteratorPrivateIteratorStack fileEngineIterators; + QDirIteratorPrivateIteratorStack<QAbstractFileEngineIterator> fileEngineIterators; + QDirIteratorPrivateIteratorStack<QFileSystemIterator> nativeIterators; + QFileInfo currentFileInfo; QFileInfo nextFileInfo; // Loop protection QSet<QString> visitedLinks; - - QDirIterator *q; }; /*! \internal */ -QDirIteratorPrivate::QDirIteratorPrivate(const QString &path, const QStringList &nameFilters, - QDir::Filters filters, QDirIterator::IteratorFlags flags) - : engine(QAbstractFileEngine::create(path)) - , path(path) +QDirIteratorPrivate::QDirIteratorPrivate(const QFileSystemEntry &entry, const QStringList &nameFilters, + QDir::Filters filters, QDirIterator::IteratorFlags flags, bool resolveEngine) + : dirEntry(entry) , nameFilters(nameFilters.contains(QLatin1String("*")) ? QStringList() : nameFilters) , filters(QDir::NoFilter == filters ? QDir::AllEntries : filters) , iteratorFlags(flags) @@ -164,22 +169,19 @@ QDirIteratorPrivate::QDirIteratorPrivate(const QString &path, const QStringList (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard)); #endif + QFileSystemMetaData metaData; + if (resolveEngine) + engine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData)); + QFileInfo fileInfo(new QFileInfoPrivate(dirEntry, metaData)); // Populate fields for hasNext() and next() - pushDirectory(QFileInfo(path)); + pushDirectory(fileInfo); advance(); } /*! \internal */ -QDirIteratorPrivate::~QDirIteratorPrivate() -{ -} - -/*! - \internal -*/ void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo) { QString path = fileInfo.filePath(); @@ -201,34 +203,63 @@ void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo) } else { // No iterator; no entry list. } + } else { + QFileSystemIterator *it = new QFileSystemIterator(fileInfo.d_ptr->fileEntry, + filters, nameFilters, iteratorFlags); + nativeIterators << it; } } -/*! - \internal -*/ -void QDirIteratorPrivate::advance() +inline bool QDirIteratorPrivate::entryMatches(const QString & fileName, const QFileInfo &fileInfo) { - while (!fileEngineIterators.isEmpty()) { + checkAndPushDirectory(fileInfo); - // Find the next valid iterator that matches the filters. - while (fileEngineIterators.top()->hasNext()) { - QAbstractFileEngineIterator *it = fileEngineIterators.top(); - it->next(); + if (matchesFilters(fileName, fileInfo)) { + currentFileInfo = nextFileInfo; + nextFileInfo = fileInfo; - const QFileInfo info = it->currentFileInfo(); - checkAndPushDirectory(it->currentFileInfo()); + //We found a matching entry. + return true; + } - if (matchesFilters(it->currentFileName(), info)) { - currentFileInfo = nextFileInfo; - nextFileInfo = info; + return false; +} - //We found a matching entry. - return; +/*! + \internal +*/ +void QDirIteratorPrivate::advance() +{ + if (engine) { + while (!fileEngineIterators.isEmpty()) { + // Find the next valid iterator that matches the filters. + QAbstractFileEngineIterator *it; + while (it = fileEngineIterators.top(), it->hasNext()) { + it->next(); + if (entryMatches(it->currentFileName(), it->currentFileInfo())) + return; } + + fileEngineIterators.pop(); + delete it; } + } else { + QFileSystemEntry nextEntry; + QFileSystemMetaData nextMetaData; + + while (!nativeIterators.isEmpty()) { + // Find the next valid iterator that matches the filters. + QFileSystemIterator *it; + while (it = nativeIterators.top(), it->advance(nextEntry, nextMetaData)) { + QFileInfo info(new QFileInfoPrivate(nextEntry, nextMetaData)); + + if (entryMatches(nextEntry.fileName(), info)) + return; + } - delete fileEngineIterators.pop(); + nativeIterators.pop(); + delete it; + } } currentFileInfo = nextFileInfo; @@ -262,7 +293,8 @@ void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo) return; // Stop link loops - if (visitedLinks.contains(fileInfo.canonicalFilePath())) + if (!visitedLinks.isEmpty() && + visitedLinks.contains(fileInfo.canonicalFilePath())) return; pushDirectory(fileInfo); @@ -373,9 +405,11 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags) - : d(new QDirIteratorPrivate(dir.path(), dir.nameFilters(), dir.filter(), flags)) { - d->q = this; + // little trick to get hold of the QDirPrivate while there is no API on QDir to give it to us + class MyQDir : public QDir { public: const QDirPrivate *priv() const { return d_ptr.constData(); } }; + const QDirPrivate *other = static_cast<const MyQDir*>(&dir)->priv(); + d.reset(new QDirIteratorPrivate(other->dirEntry, other->nameFilters, other->filters, flags, !other->fileEngine.isNull())); } /*! @@ -395,9 +429,8 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags) \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags) - : d(new QDirIteratorPrivate(path, QStringList(), filters, flags)) + : d(new QDirIteratorPrivate(QFileSystemEntry(path), QStringList(), filters, flags)) { - d->q = this; } /*! @@ -413,9 +446,8 @@ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorF \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags) - : d(new QDirIteratorPrivate(path, QStringList(), QDir::NoFilter, flags)) + : d(new QDirIteratorPrivate(QFileSystemEntry(path), QStringList(), QDir::NoFilter, flags)) { - d->q = this; } /*! @@ -436,9 +468,8 @@ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags) */ QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters, QDir::Filters filters, IteratorFlags flags) - : d(new QDirIteratorPrivate(path, nameFilters, filters, flags)) + : d(new QDirIteratorPrivate(QFileSystemEntry(path), nameFilters, filters, flags)) { - d->q = this; } /*! @@ -472,7 +503,10 @@ QString QDirIterator::next() */ bool QDirIterator::hasNext() const { - return !d->fileEngineIterators.isEmpty(); + if (d->engine) + return !d->fileEngineIterators.isEmpty(); + else + return !d->nativeIterators.isEmpty(); } /*! @@ -515,7 +549,7 @@ QFileInfo QDirIterator::fileInfo() const */ QString QDirIterator::path() const { - return d->path; + return d->dirEntry.filePath(); } QT_END_NAMESPACE diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 50e9a8f..85e78a6 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -48,6 +48,7 @@ #include "qfileinfo.h" #include "private/qiodevice_p.h" #include "private/qfile_p.h" +#include "private/qsystemerror_p.h" #if defined(QT_BUILD_CORE_LIB) # include "qcoreapplication.h" #endif @@ -992,8 +993,14 @@ bool QFile::open(OpenMode mode) return false; } +#ifdef Q_OS_SYMBIAN + // For symbian, the unbuffered flag is used to control write-behind cache behaviour + if (fileEngine()->open(mode)) +#else // QIODevice provides the buffering, so there's no need to request it from the file engine. - if (fileEngine()->open(mode | QIODevice::Unbuffered)) { + if (fileEngine()->open(mode | QIODevice::Unbuffered)) +#endif + { QIODevice::open(mode); if (mode & Append) seek(size()); @@ -1223,6 +1230,7 @@ bool QFile::unmap(uchar *address) d->setError(d->fileEngine->error(), d->fileEngine->errorString()); return success; } + d->setError(PermissionsError, tr("No file engine available or engine does not support UnMapExtension")); return false; } @@ -1477,7 +1485,17 @@ bool QFile::atEnd() const } /*! - \reimp + For random-access devices, this function sets the current position + to \a pos, returning true on success, or false if an error occurred. + For sequential devices, the default behavior is to do nothing and + return false. + + Seeking beyond the end of a file: + If the position is beyond the end of a file, then seek() shall not + immediately extend the file. If a write is performed at this position, + then the file shall be extended. The content of the file between the + previous end of file and the newly written data is UNDEFINED and + varies between platforms and file systems. */ bool QFile::seek(qint64 off) diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 7eca212..9041c94 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -51,7 +51,47 @@ QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const { if (cache_enabled && !fileNames[(int)name].isNull()) return fileNames[(int)name]; - QString ret = fileEngine->fileName(name); + + QString ret; + if (fileEngine == 0) { // local file; use the QFileSystemEngine directly + switch (name) { + case QAbstractFileEngine::CanonicalName: + case QAbstractFileEngine::CanonicalPathName: { + QFileSystemEntry entry = QFileSystemEngine::canonicalName(fileEntry, metaData); + if (cache_enabled) { // be smart and store both + fileNames[QAbstractFileEngine::CanonicalName] = entry.filePath(); + fileNames[QAbstractFileEngine::CanonicalPathName] = entry.path(); + } + if (name == QAbstractFileEngine::CanonicalName) + ret = entry.filePath(); + else + ret = entry.path(); + break; + } + case QAbstractFileEngine::LinkName: + ret = QFileSystemEngine::getLinkTarget(fileEntry, metaData).filePath(); + break; + case QAbstractFileEngine::BundleName: + ret = QFileSystemEngine::bundleName(fileEntry); + break; + case QAbstractFileEngine::AbsoluteName: + case QAbstractFileEngine::AbsolutePathName: { + QFileSystemEntry entry = QFileSystemEngine::absoluteName(fileEntry); + if (cache_enabled) { // be smart and store both + fileNames[QAbstractFileEngine::AbsoluteName] = entry.filePath(); + fileNames[QAbstractFileEngine::AbsolutePathName] = entry.path(); + } + if (name == QAbstractFileEngine::AbsoluteName) + ret = entry.filePath(); + else + ret = entry.path(); + break; + } + default: break; + } + } else { + ret = fileEngine->fileName(name); + } if (ret.isNull()) ret = QLatin1String(""); if (cache_enabled) @@ -63,7 +103,19 @@ QString QFileInfoPrivate::getFileOwner(QAbstractFileEngine::FileOwner own) const { if (cache_enabled && !fileOwners[(int)own].isNull()) return fileOwners[(int)own]; - QString ret = fileEngine->owner(own); + QString ret; + if (fileEngine == 0) { + switch (own) { + case QAbstractFileEngine::OwnerUser: + ret = QFileSystemEngine::resolveUserName(fileEntry, metaData); + break; + case QAbstractFileEngine::OwnerGroup: + ret = QFileSystemEngine::resolveGroupName(fileEntry, metaData); + break; + } + } else { + ret = fileEngine->owner(own); + } if (ret.isNull()) ret = QLatin1String(""); if (cache_enabled) @@ -73,6 +125,7 @@ QString QFileInfoPrivate::getFileOwner(QAbstractFileEngine::FileOwner own) const uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) const { + Q_ASSERT(fileEngine); // should never be called when using the native FS // We split the testing into tests for for LinkType, BundleType, PermsMask // and the rest. // Tests for file permissions on Windows can be slow, expecially on network @@ -133,6 +186,7 @@ uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) cons QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) const { + Q_ASSERT(fileEngine); // should never be called when using the native FS if (!cache_enabled) clearFlags(); uint cf; @@ -237,6 +291,13 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) */ /*! + \internal +*/ +QFileInfo::QFileInfo(QFileInfoPrivate *p) : d_ptr(p) +{ +} + +/*! Constructs an empty QFileInfo object. Note that an empty QFileInfo object contain no file reference. @@ -330,23 +391,22 @@ bool QFileInfo::operator==(const QFileInfo &fileinfo) const return true; if (d->isDefaultConstructed || fileinfo.d_ptr->isDefaultConstructed) return false; - if (d->fileEngine->caseSensitive() != fileinfo.d_ptr->fileEngine->caseSensitive()) - return false; - if (fileinfo.size() == size()) { //if the size isn't the same... - QString file1 = canonicalFilePath(), - file2 = fileinfo.canonicalFilePath(); - if (file1.length() == file2.length()) { - if (!fileinfo.d_ptr->fileEngine->caseSensitive()) { - for (int i = 0; i < file1.length(); i++) { - if (file1.at(i).toLower() != file2.at(i).toLower()) - return false; - } - return true; - } - return (file1 == file2); - } + Qt::CaseSensitivity sensitive; + if (d->fileEngine == 0 || fileinfo.d_ptr->fileEngine == 0) { + if (d->fileEngine != fileinfo.d_ptr->fileEngine) // one is native, the other is a custom file-engine + return false; + + sensitive = QFileSystemEngine::isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive; + } else { + if (d->fileEngine->caseSensitive() != fileinfo.d_ptr->fileEngine->caseSensitive()) + return false; + sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive; } - return false; + + if (fileinfo.size() != size()) //if the size isn't the same... + return false; + + return canonicalFilePath().compare(fileinfo.canonicalFilePath(), sensitive) == 0; } /*! @@ -502,7 +562,7 @@ QString QFileInfo::absolutePath() const if (d->isDefaultConstructed) { return QLatin1String(""); - } else if (d->fileName.isEmpty()) { + } else if (d->fileEntry.isEmpty()) { qWarning("QFileInfo::absolutePath: Constructed with empty filename"); return QLatin1String(""); } @@ -539,7 +599,7 @@ QString QFileInfo::path() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QLatin1String(""); - return d->getFileName(QAbstractFileEngine::PathName); + return d->fileEntry.path(); } /*! @@ -563,6 +623,8 @@ bool QFileInfo::isRelative() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return true; + if (d->fileEngine == 0) + return d->fileEntry.isRelative(); return d->fileEngine->isRelativePath(); } @@ -576,12 +638,10 @@ bool QFileInfo::isRelative() const bool QFileInfo::makeAbsolute() { if (d_ptr.constData()->isDefaultConstructed - || !d_ptr.constData()->fileEngine->isRelativePath()) + || !d_ptr.constData()->fileEntry.isRelative()) return false; - QString absFileName = d_ptr.constData()->getFileName(QAbstractFileEngine::AbsoluteName); - // QSharedDataPointer::operator->() will detach. - setFile(absFileName); + setFile(absoluteFilePath()); return true; } @@ -596,6 +656,11 @@ bool QFileInfo::exists() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ExistsAttribute)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ExistsAttribute); + return d->metaData.exists(); + } return d->getFileFlags(QAbstractFileEngine::ExistsFlag); } @@ -623,7 +688,7 @@ QString QFileInfo::filePath() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QLatin1String(""); - return d->getFileName(QAbstractFileEngine::DefaultName); + return d->fileEntry.filePath(); } /*! @@ -642,7 +707,7 @@ QString QFileInfo::fileName() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QLatin1String(""); - return d->getFileName(QAbstractFileEngine::BaseName); + return d->fileEntry.fileName(); } /*! @@ -686,7 +751,7 @@ QString QFileInfo::baseName() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QLatin1String(""); - return d->getFileName(QAbstractFileEngine::BaseName).section(QLatin1Char('.'), 0, 0); + return d->fileEntry.baseName(); } /*! @@ -705,9 +770,7 @@ QString QFileInfo::completeBaseName() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QLatin1String(""); - QString name = d->getFileName(QAbstractFileEngine::BaseName); - int index = name.lastIndexOf(QLatin1Char('.')); - return (index == -1) ? name : name.left(index); + return d->fileEntry.completeBaseName(); } /*! @@ -726,11 +789,7 @@ QString QFileInfo::completeSuffix() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QLatin1String(""); - QString fileName = d->getFileName(QAbstractFileEngine::BaseName); - int firstDot = fileName.indexOf(QLatin1Char('.')); - if (firstDot == -1) - return QLatin1String(""); - return fileName.mid(firstDot + 1); + return d->fileEntry.completeSuffix(); } /*! @@ -753,11 +812,7 @@ QString QFileInfo::suffix() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QLatin1String(""); - QString fileName = d->getFileName(QAbstractFileEngine::BaseName); - int lastDot = fileName.lastIndexOf(QLatin1Char('.')); - if (lastDot == -1) - return QLatin1String(""); - return fileName.mid(lastDot + 1); + return d->fileEntry.suffix(); } @@ -781,8 +836,9 @@ QString QFileInfo::suffix() const */ QDir QFileInfo::dir() const { + Q_D(const QFileInfo); // ### Qt5: Maybe rename this to parentDirectory(), considering what it actually do? - return QDir(path()); + return QDir(d->fileEntry.path()); } /*! @@ -818,6 +874,11 @@ bool QFileInfo::isReadable() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserReadPermission)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserReadPermission); + return (d->metaData.permissions() & QFile::ReadUser) != 0; + } return d->getFileFlags(QAbstractFileEngine::ReadUserPerm); } @@ -831,6 +892,11 @@ bool QFileInfo::isWritable() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserWritePermission)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserWritePermission); + return (d->metaData.permissions() & QFile::WriteUser) != 0; + } return d->getFileFlags(QAbstractFileEngine::WriteUserPerm); } @@ -844,6 +910,11 @@ bool QFileInfo::isExecutable() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserExecutePermission)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserExecutePermission); + return (d->metaData.permissions() & QFile::ExeUser) != 0; + } return d->getFileFlags(QAbstractFileEngine::ExeUserPerm); } @@ -858,6 +929,11 @@ bool QFileInfo::isHidden() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::HiddenAttribute)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::HiddenAttribute); + return d->metaData.isHidden(); + } return d->getFileFlags(QAbstractFileEngine::HiddenFlag); } @@ -873,6 +949,11 @@ bool QFileInfo::isFile() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::FileType)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::FileType); + return d->metaData.isFile(); + } return d->getFileFlags(QAbstractFileEngine::FileType); } @@ -887,6 +968,11 @@ bool QFileInfo::isDir() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::DirectoryType)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::DirectoryType); + return d->metaData.isDirectory(); + } return d->getFileFlags(QAbstractFileEngine::DirectoryType); } @@ -903,6 +989,11 @@ bool QFileInfo::isBundle() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::BundleType)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::BundleType); + return d->metaData.isBundle(); + } return d->getFileFlags(QAbstractFileEngine::BundleType); } @@ -928,6 +1019,11 @@ bool QFileInfo::isSymLink() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::LegacyLinkType)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::LegacyLinkType); + return d->metaData.isLegacyLink(); + } return d->getFileFlags(QAbstractFileEngine::LinkType); } @@ -941,6 +1037,20 @@ bool QFileInfo::isRoot() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return true; + if (d->fileEngine == 0) { + if (d->fileEntry.isRoot()) { +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + //the path is a drive root, but the drive may not exist + //for backward compatibility, return true only if the drive exists + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ExistsAttribute)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ExistsAttribute); + return d->metaData.exists(); +#else + return true; +#endif + } + return false; + } return d->getFileFlags(QAbstractFileEngine::RootFlag); } @@ -1003,6 +1113,11 @@ uint QFileInfo::ownerId() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return 0; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserId)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserId); + return d->metaData.userId(); + } return d->fileEngine->ownerId(QAbstractFileEngine::OwnerUser); } @@ -1037,6 +1152,11 @@ uint QFileInfo::groupId() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return 0; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::GroupId)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::GroupId); + return d->metaData.groupId(); + } return d->fileEngine->ownerId(QAbstractFileEngine::OwnerGroup); } @@ -1058,6 +1178,13 @@ bool QFileInfo::permission(QFile::Permissions permissions) const Q_D(const QFileInfo); if (d->isDefaultConstructed) return false; + if (d->fileEngine == 0) { + // the QFileSystemMetaData::MetaDataFlag and QFile::Permissions overlap, so just static cast. + QFileSystemMetaData::MetaDataFlag permissionFlags = static_cast<QFileSystemMetaData::MetaDataFlag>((int)permissions); + if (!d->cache_enabled || !d->metaData.hasFlags(permissionFlags)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, permissionFlags); + return (d->metaData.permissions() & permissions) == permissions; + } return d->getFileFlags(QAbstractFileEngine::FileFlags((int)permissions)) == (uint)permissions; } @@ -1070,6 +1197,11 @@ QFile::Permissions QFileInfo::permissions() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return 0; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::Permissions)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::Permissions); + return d->metaData.permissions(); + } return QFile::Permissions(d->getFileFlags(QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask); } @@ -1085,6 +1217,11 @@ qint64 QFileInfo::size() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return 0; + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::SizeAttribute)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::SizeAttribute); + return d->metaData.size(); + } if (!d->getCachedFlag(QFileInfoPrivate::CachedSize)) { d->setCachedFlag(QFileInfoPrivate::CachedSize); d->fileSize = d->fileEngine->size(); @@ -1110,6 +1247,11 @@ QDateTime QFileInfo::created() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QDateTime(); + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::CreationTime)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::CreationTime); + return d->metaData.creationTime(); + } return d->getFileTime(QAbstractFileEngine::CreationTime); } @@ -1123,6 +1265,11 @@ QDateTime QFileInfo::lastModified() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QDateTime(); + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ModificationTime)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ModificationTime); + return d->metaData.modificationTime(); + } return d->getFileTime(QAbstractFileEngine::ModificationTime); } @@ -1139,6 +1286,11 @@ QDateTime QFileInfo::lastRead() const Q_D(const QFileInfo); if (d->isDefaultConstructed) return QDateTime(); + if (d->fileEngine == 0) { + if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::AccessTime)) + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::AccessTime); + return d->metaData.accessTime(); + } return d->getFileTime(QAbstractFileEngine::AccessTime); } diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h index aec7543..3eff208 100644 --- a/src/corelib/io/qfileinfo.h +++ b/src/corelib/io/qfileinfo.h @@ -53,12 +53,16 @@ QT_BEGIN_NAMESPACE QT_MODULE(Core) class QDir; +class QDirIteratorPrivate; class QDateTime; class QFileInfoPrivate; class Q_CORE_EXPORT QFileInfo { + friend class QDirIteratorPrivate; public: + explicit QFileInfo(QFileInfoPrivate *d); + QFileInfo(); QFileInfo(const QString &file); QFileInfo(const QFile &file); diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h index b9b1092..869a7a6 100644 --- a/src/corelib/io/qfileinfo_p.h +++ b/src/corelib/io/qfileinfo_p.h @@ -58,13 +58,16 @@ #include "qdatetime.h" #include "qatomic.h" #include "qshareddata.h" +#include "qfilesystemengine_p.h" + +#include <QtCore/private/qfilesystementry_p.h> +#include <QtCore/private/qfilesystemmetadata_p.h> QT_BEGIN_NAMESPACE class QFileInfoPrivate : public QSharedData { public: - enum { CachedFileFlags=0x01, CachedLinkTypeFlag=0x02, CachedBundleTypeFlag=0x04, CachedMTime=0x10, CachedCTime=0x20, CachedATime=0x40, CachedSize =0x08, CachedPerms=0x80 }; @@ -76,8 +79,10 @@ public: cache_enabled(true), fileFlags(0), fileSize(0) {} inline QFileInfoPrivate(const QFileInfoPrivate ©) - : QSharedData(copy), fileEngine(QAbstractFileEngine::create(copy.fileName)), - fileName(copy.fileName), + : QSharedData(copy), + fileEntry(copy.fileEntry), + metaData(copy.metaData), + fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)), cachedFlags(0), #ifndef QT_NO_FSFILEENGINE isDefaultConstructed(false), @@ -87,8 +92,8 @@ public: cache_enabled(copy.cache_enabled), fileFlags(0), fileSize(0) {} inline QFileInfoPrivate(const QString &file) - : QSharedData(), fileEngine(QAbstractFileEngine::create(file)), - fileName(file), + : fileEntry(QDir::fromNativeSeparators(file)), + fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)), cachedFlags(0), #ifndef QT_NO_FSFILEENGINE isDefaultConstructed(false), @@ -99,6 +104,16 @@ public: { } + inline QFileInfoPrivate(const QFileSystemEntry &file, const QFileSystemMetaData &data) + : QSharedData(), + fileEntry(file), + metaData(data), + cachedFlags(0), + isDefaultConstructed(false), + cache_enabled(true), fileFlags(0), fileSize(0) + { + } + inline void clearFlags() const { fileFlags = 0; cachedFlags = 0; @@ -106,6 +121,7 @@ public: (void)fileEngine->fileFlags(QAbstractFileEngine::Refresh); } inline void clear() { + metaData.clear(); clearFlags(); for (int i = QAbstractFileEngine::NFileNames - 1 ; i >= 0 ; --i) fileNames[i].clear(); @@ -118,9 +134,11 @@ public: QString getFileName(QAbstractFileEngine::FileName) const; QString getFileOwner(QAbstractFileEngine::FileOwner own) const; + QFileSystemEntry fileEntry; + mutable QFileSystemMetaData metaData; + QScopedPointer<QAbstractFileEngine> const fileEngine; - mutable QString fileName; mutable QString fileNames[QAbstractFileEngine::NFileNames]; mutable QString fileOwners[2]; @@ -134,6 +152,7 @@ public: { return cache_enabled ? (cachedFlags & c) : 0; } inline void setCachedFlag(uint c) const { if (cache_enabled) cachedFlags |= c; } + }; QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp new file mode 100644 index 0000000..d9d802e --- /dev/null +++ b/src/corelib/io/qfilesystemengine.cpp @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfilesystemengine_p.h" +#include <QtCore/qdir.h> +#include <QtCore/qset.h> +#include <QtCore/qstringbuilder.h> +#include <QtCore/private/qabstractfileengine_p.h> +#ifdef QT_BUILD_CORE_LIB +#include <QtCore/private/qresource_p.h> +#endif + +QT_BEGIN_NAMESPACE + +/*! + \internal + + Returns the canonicalized form of \a path (i.e., with all symlinks + resolved, and all redundant path elements removed. +*/ +QString QFileSystemEngine::slowCanonicalized(const QString &path) +{ + if (path.isEmpty()) + return path; + + QFileInfo fi; + const QChar slash(QLatin1Char('/')); + QString tmpPath = path; + int separatorPos = 0; + QSet<QString> nonSymlinks; + QSet<QString> known; + + known.insert(path); + do { +#ifdef Q_OS_WIN + if (separatorPos == 0) { + if (tmpPath.size() >= 2 && tmpPath.at(0) == slash && tmpPath.at(1) == slash) { + // UNC, skip past the first two elements + separatorPos = tmpPath.indexOf(slash, 2); + } else if (tmpPath.size() >= 3 && tmpPath.at(1) == QLatin1Char(':') && tmpPath.at(2) == slash) { + // volume root, skip since it can not be a symlink + separatorPos = 2; + } + } + if (separatorPos != -1) +#endif + separatorPos = tmpPath.indexOf(slash, separatorPos + 1); + QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos); + if ( +#ifdef Q_OS_SYMBIAN + // Symbian doesn't support directory symlinks, so do not check for link unless we + // are handling the last path element. This not only slightly improves performance, + // but also saves us from lot of unnecessary platform security check failures + // when dealing with files under *:/private directories. + separatorPos == -1 && +#endif + !nonSymlinks.contains(prefix)) { + fi.setFile(prefix); + if (fi.isSymLink()) { + QString target = fi.symLinkTarget(); + if(QFileInfo(target).isRelative()) + target = fi.absolutePath() + slash + target; + if (separatorPos != -1) { + if (fi.isDir() && !target.endsWith(slash)) + target.append(slash); + target.append(tmpPath.mid(separatorPos)); + } + tmpPath = QDir::cleanPath(target); + separatorPos = 0; + + if (known.contains(tmpPath)) + return QString(); + known.insert(tmpPath); + } else { + nonSymlinks.insert(prefix); + } + } + } while (separatorPos != -1); + + return QDir::cleanPath(tmpPath); +} + +static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry) +{ + if (resolvingEntry) { + if (!QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute) + || !data.exists()) { + data.clear(); + return false; + } + } + + return true; +} + +static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEntry) +{ + if (resolvingEntry) { + if (!(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) { + delete engine; + engine = 0; + return false; + } + } + + return true; +} + +static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data, + QAbstractFileEngine *&engine, bool resolvingEntry = false) +{ + QString const &filePath = entry.filePath(); + if ((engine = qt_custom_file_engine_handler_create(filePath))) + return _q_checkEntry(engine, resolvingEntry); + +#if defined(QT_BUILD_CORE_LIB) + for (int prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) { + QChar const ch = filePath[prefixSeparator]; + if (ch == QLatin1Char('/')) + break; + + if (ch == QLatin1Char(':')) { + if (prefixSeparator == 0) { + engine = new QResourceFileEngine(filePath); + return _q_checkEntry(engine, resolvingEntry); + } + + if (prefixSeparator == 1) + break; + + const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator)); + for (int i = 0; i < paths.count(); i++) { + entry = QFileSystemEntry(paths.at(i) % QLatin1Char('/') % filePath.mid(prefixSeparator + 1)); + // Recurse! + if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true)) + return true; + } + + // entry may have been clobbered at this point. + return false; + } + + // There's no need to fully validate the prefix here. Consulting the + // unicode tables could be expensive and validation is already + // performed in QDir::setSearchPaths. + // + // if (!ch.isLetterOrNumber()) + // break; + } +#endif // defined(QT_BUILD_CORE_LIB) + + return _q_checkEntry(entry, data, resolvingEntry); +} + +/*! + \internal + + Resolves the \a entry (see QDir::searchPaths) and returns an engine for + it, but never a QFSFileEngine. + + \returns a file engine that can be used to access the entry. Returns 0 if + QFileSystemEngine API should be used to query and interact with the file + system object. +*/ +QAbstractFileEngine *QFileSystemEngine::resolveEntryAndCreateLegacyEngine( + QFileSystemEntry &entry, QFileSystemMetaData &data) { + QFileSystemEntry copy = entry; + QAbstractFileEngine *engine = 0; + + if (_q_resolveEntryAndCreateLegacyEngine_recursive(copy, data, engine)) + // Reset entry to resolved copy. + entry = copy; + else + data.clear(); + + return engine; +} + +//these unix functions are in this file, because they are shared by symbian port +//for open C file handles. +#ifdef Q_OS_UNIX +//static +bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data) +{ + data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags; + data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags; + + QT_STATBUF statBuffer; + if (QT_FSTAT(fd, &statBuffer) == 0) { + data.fillFromStatBuf(statBuffer); + return true; + } + + return false; +} + +void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer) +{ + // Permissions + if (statBuffer.st_mode & S_IRUSR) + entryFlags |= QFileSystemMetaData::OwnerReadPermission; + if (statBuffer.st_mode & S_IWUSR) + entryFlags |= QFileSystemMetaData::OwnerWritePermission; + if (statBuffer.st_mode & S_IXUSR) + entryFlags |= QFileSystemMetaData::OwnerExecutePermission; + + if (statBuffer.st_mode & S_IRGRP) + entryFlags |= QFileSystemMetaData::GroupReadPermission; + if (statBuffer.st_mode & S_IWGRP) + entryFlags |= QFileSystemMetaData::GroupWritePermission; + if (statBuffer.st_mode & S_IXGRP) + entryFlags |= QFileSystemMetaData::GroupExecutePermission; + + if (statBuffer.st_mode & S_IROTH) + entryFlags |= QFileSystemMetaData::OtherReadPermission; + if (statBuffer.st_mode & S_IWOTH) + entryFlags |= QFileSystemMetaData::OtherWritePermission; + if (statBuffer.st_mode & S_IXOTH) + entryFlags |= QFileSystemMetaData::OtherExecutePermission; + + // Type + if ((statBuffer.st_mode & S_IFMT) == S_IFREG) + entryFlags |= QFileSystemMetaData::FileType; + else if ((statBuffer.st_mode & S_IFMT) == S_IFDIR) + entryFlags |= QFileSystemMetaData::DirectoryType; + else + entryFlags |= QFileSystemMetaData::SequentialType; + + // Attributes + entryFlags |= QFileSystemMetaData::ExistsAttribute; + size_ = statBuffer.st_size; +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) \ + && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + if (statBuffer.st_flags & UF_HIDDEN) { + entryFlags |= QFileSystemMetaData::HiddenAttribute; + knownFlagsMask |= QFileSystemMetaData::HiddenAttribute; + } +#endif + + // Times +#ifdef Q_OS_SYMBIAN + modificationTime_ = qt_symbian_time_t_To_TTime(statBuffer.st_mtime); +#else + creationTime_ = statBuffer.st_ctime ? statBuffer.st_ctime : statBuffer.st_mtime; + modificationTime_ = statBuffer.st_mtime; + accessTime_ = statBuffer.st_atime; + userId_ = statBuffer.st_uid; + groupId_ = statBuffer.st_gid; +#endif +} + +void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry) +{ + // ### This will clear all entry flags and knownFlagsMask + switch (entry.d_type) + { + case DT_DIR: + knownFlagsMask = QFileSystemMetaData::LinkType + | QFileSystemMetaData::FileType + | QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::SequentialType + | QFileSystemMetaData::ExistsAttribute; + + entryFlags = QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::ExistsAttribute; + + break; + + case DT_BLK: + case DT_CHR: + case DT_FIFO: + case DT_SOCK: + // ### System attribute + knownFlagsMask = QFileSystemMetaData::LinkType + | QFileSystemMetaData::FileType + | QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::BundleType + | QFileSystemMetaData::AliasType + | QFileSystemMetaData::SequentialType + | QFileSystemMetaData::ExistsAttribute; + + entryFlags = QFileSystemMetaData::SequentialType + | QFileSystemMetaData::ExistsAttribute; + + break; + + case DT_LNK: + knownFlagsMask = QFileSystemMetaData::LinkType; + entryFlags = QFileSystemMetaData::LinkType; + break; + + case DT_REG: + knownFlagsMask = QFileSystemMetaData::LinkType + | QFileSystemMetaData::FileType + | QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::BundleType + | QFileSystemMetaData::SequentialType + | QFileSystemMetaData::ExistsAttribute; + + entryFlags = QFileSystemMetaData::FileType + | QFileSystemMetaData::ExistsAttribute; + + break; + + case DT_UNKNOWN: + default: + clear(); + } +} + +#endif + +//static +QString QFileSystemEngine::resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData) +{ +#if defined (Q_OS_SYMBIAN) + Q_UNUSED(entry); + Q_UNUSED(metaData); + return QString(); +#elif defined(Q_OS_WIN) + Q_UNUSED(metaData); + return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerUser); +#else //(Q_OS_UNIX) + if (!metaData.hasFlags(QFileSystemMetaData::UserId)) + QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::UserId); + return resolveUserName(metaData.userId()); +#endif +} + +//static +QString QFileSystemEngine::resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData) +{ +#if defined (Q_OS_SYMBIAN) + Q_UNUSED(entry); + Q_UNUSED(metaData); + return QString(); +#elif defined(Q_OS_WIN) + Q_UNUSED(metaData); + return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerGroup); +#else //(Q_OS_UNIX) + if (!metaData.hasFlags(QFileSystemMetaData::GroupId)) + QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::GroupId); + return resolveGroupName(metaData.groupId()); +#endif +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemengine_mac.cpp b/src/corelib/io/qfilesystemengine_mac.cpp new file mode 100644 index 0000000..30d7fa5 --- /dev/null +++ b/src/corelib/io/qfilesystemengine_mac.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfilesystemengine_p.h" + +QT_BEGIN_NAMESPACE + +// Mac-specific implementations only! + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h new file mode 100644 index 0000000..a3ec0ab --- /dev/null +++ b/src/corelib/io/qfilesystemengine_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILESYSTEMENGINE_P_H_INCLUDED +#define QFILESYSTEMENGINE_P_H_INCLUDED + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qfile.h" +#include "qfilesystementry_p.h" +#include "qfilesystemmetadata_p.h" +#include <QtCore/private/qsystemerror_p.h> + +QT_BEGIN_NAMESPACE + +class QFileSystemEngine +{ +public: + static bool isCaseSensitive(); + + static QFileSystemEntry getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data); + static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data); + static QFileSystemEntry absoluteName(const QFileSystemEntry &entry); + static QString resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &data); + static QString resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &data); + +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + static QString resolveUserName(uint userId); + static QString resolveGroupName(uint groupId); +#endif + +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) + static QString bundleName(const QFileSystemEntry &entry); +#else + static QString bundleName(const QFileSystemEntry &entry) { Q_UNUSED(entry) return QString(); } +#endif + + static bool fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, + QFileSystemMetaData::MetaDataFlags what); +#if defined(Q_OS_UNIX) + static bool fillMetaData(int fd, QFileSystemMetaData &data); // what = PosixStatFlags +#endif +#if defined(Q_OS_WIN) + + static bool uncListSharesOnServer(const QString &server, QStringList *list); //Used also by QFSFileEngineIterator::hasNext() + static bool fillMetaData(int fd, QFileSystemMetaData &data, + QFileSystemMetaData::MetaDataFlags what); + static bool fillMetaData(HANDLE fHandle, QFileSystemMetaData &data, + QFileSystemMetaData::MetaDataFlags what); + static bool fillPermissions(const QFileSystemEntry &entry, QFileSystemMetaData &data, + QFileSystemMetaData::MetaDataFlags what); + static QString owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own); + static QString nativeAbsoluteFilePath(const QString &path); +#endif + //homePath, rootPath and tempPath shall return clean paths + static QString homePath(); + static QString rootPath(); + static QString tempPath(); + + static bool createDirectory(const QFileSystemEntry &entry, bool createParents); + static bool removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents); + + static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); + + static bool copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); + static bool renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); + static bool removeFile(const QFileSystemEntry &entry, QSystemError &error); + + static bool setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, + QFileSystemMetaData *data = 0); + + static bool setCurrentPath(const QFileSystemEntry &entry); + static QFileSystemEntry currentPath(); + + static QAbstractFileEngine *resolveEntryAndCreateLegacyEngine(QFileSystemEntry &entry, + QFileSystemMetaData &data); +private: + static QString slowCanonicalized(const QString &path); +#if defined(Q_OS_WIN) + static void clearWinStatData(QFileSystemMetaData &data); +#endif +}; + +QT_END_NAMESPACE + +#endif // include guard diff --git a/src/corelib/io/qfilesystemengine_symbian.cpp b/src/corelib/io/qfilesystemengine_symbian.cpp new file mode 100644 index 0000000..84c3aa1 --- /dev/null +++ b/src/corelib/io/qfilesystemengine_symbian.cpp @@ -0,0 +1,408 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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 = (orig.contains(QLatin1String("/../")) || orig.contains(QLatin1String("/./")) || + orig.contains(QLatin1String("//")) || + orig.endsWith(QLatin1String("/..")) || orig.endsWith(QLatin1String("/."))); + 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 new file mode 100644 index 0000000..40fb0c0 --- /dev/null +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -0,0 +1,655 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qfilesystemengine_p.h" +#include "qplatformdefs.h" +#include "qfsfileengine.h" +#include "qfile.h" + +#include <QtCore/qvarlengtharray.h> + +#include <stdlib.h> // for realpath() +#include <unistd.h> +#include <stdio.h> +#include <errno.h> + + +#if defined(Q_OS_MAC) +# include <QtCore/private/qcore_mac_p.h> +#endif + +QT_BEGIN_NAMESPACE + +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) +static inline bool _q_isMacHidden(const char *nativePath) +{ + OSErr err; + + FSRef fsRef; + err = FSPathMakeRefWithOptions(reinterpret_cast<const UInt8 *>(nativePath), + kFSPathMakeRefDoNotFollowLeafSymlink, &fsRef, 0); + if (err != noErr) + return false; + + FSCatalogInfo catInfo; + err = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL); + if (err != noErr) + return false; + + FileInfo * const fileInfo = reinterpret_cast<FileInfo*>(&catInfo.finderInfo); + return (fileInfo->finderFlags & kIsInvisible); +} +#else +static inline bool _q_isMacHidden(const char *nativePath) +{ + Q_UNUSED(nativePath); + // no-op + return false; +} +#endif + +bool QFileSystemEngine::isCaseSensitive() +{ + return true; +} + +//static +QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data) +{ +#if defined(__GLIBC__) && !defined(PATH_MAX) +#define PATH_CHUNK_SIZE 256 + char *s = 0; + int len = -1; + int size = PATH_CHUNK_SIZE; + + while (1) { + s = (char *) ::realloc(s, size); + Q_CHECK_PTR(s); + len = ::readlink(link.nativeFilePath().constData(), s, size); + if (len < 0) { + ::free(s); + break; + } + if (len < size) { + break; + } + size *= 2; + } +#else + char s[PATH_MAX+1]; + int len = readlink(link.nativeFilePath().constData(), s, PATH_MAX); +#endif + if (len > 0) { + QString ret; + if (!data.hasFlags(QFileSystemMetaData::DirectoryType)) + fillMetaData(link, data, QFileSystemMetaData::DirectoryType); + if (data.isDirectory() && s[0] != '/') { + QDir parent(link.filePath()); + parent.cdUp(); + ret = parent.path(); + if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/'))) + ret += QLatin1Char('/'); + } + s[len] = '\0'; + ret += QFile::decodeName(QByteArray(s)); +#if defined(__GLIBC__) && !defined(PATH_MAX) + ::free(s); +#endif + + if (!ret.startsWith(QLatin1Char('/'))) { + if (link.filePath().startsWith(QLatin1Char('/'))) { + ret.prepend(link.filePath().left(link.filePath().lastIndexOf(QLatin1Char('/'))) + + QLatin1Char('/')); + } else { + ret.prepend(QDir::currentPath() + QLatin1Char('/')); + } + } + ret = QDir::cleanPath(ret); + if (ret.size() > 1 && ret.endsWith(QLatin1Char('/'))) + ret.chop(1); + return QFileSystemEntry(ret); + } +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) + { + FSRef fref; + if (FSPathMakeRef((const UInt8 *)QFile::encodeName(QDir::cleanPath(link.filePath())).data(), &fref, 0) == noErr) { + // TODO get the meta data info from the QFileSystemMetaData object + Boolean isAlias, isFolder; + if (FSResolveAliasFile(&fref, true, &isFolder, &isAlias) == noErr && isAlias) { + AliasHandle alias; + if (FSNewAlias(0, &fref, &alias) == noErr && alias) { + QCFString cfstr; + if (FSCopyAliasInfo(alias, 0, 0, &cfstr, 0, 0) == noErr) + return QFileSystemEntry(QCFString::toQString(cfstr)); + } + } + } + } +#endif + return QFileSystemEntry(); +} + +//static +QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data) +{ + if (entry.isEmpty() || entry.isRoot()) + return entry; + +#ifdef __UCLIBC__ + return QFileSystemEntry::slowCanonicalName(entry); +#else + char *ret = 0; +# if defined(Q_OS_MAC) && !defined(QT_NO_CORESERVICES) + // Mac OS X 10.5.x doesn't support the realpath(X,0) extension we use here. + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) { + ret = realpath(entry.nativeFilePath().constData(), (char*)0); + } else { + // on 10.5 we can use FSRef to resolve the file path. + QString path = QDir::cleanPath(entry.filePath()); + FSRef fsref; + if (FSPathMakeRef((const UInt8 *)path.toUtf8().data(), &fsref, 0) == noErr) { + CFURLRef urlref = CFURLCreateFromFSRef(NULL, &fsref); + CFStringRef canonicalPath = CFURLCopyFileSystemPath(urlref, kCFURLPOSIXPathStyle); + QString ret = QCFString::toQString(canonicalPath); + CFRelease(canonicalPath); + CFRelease(urlref); + return QFileSystemEntry(ret); + } + } +# else + ret = realpath(entry.nativeFilePath().constData(), (char*)0); +# endif + if (ret) { + data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute; + data.entryFlags |= QFileSystemMetaData::ExistsAttribute; + QString canonicalPath = QDir::cleanPath(QString::fromLocal8Bit(ret)); + free(ret); + return QFileSystemEntry(canonicalPath); + } else if (errno == ENOENT) { // file doesn't exist + data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute; + data.entryFlags &= ~(QFileSystemMetaData::ExistsAttribute); + return QFileSystemEntry(); + } + return entry; +#endif +} + +//static +QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry) +{ + if (entry.isAbsolute()) + return entry; + + QByteArray orig = entry.nativeFilePath(); + QByteArray result; + if (orig.isEmpty() || !orig.startsWith('/')) { + QFileSystemEntry cur(currentPath()); + result = cur.nativeFilePath(); + } + if (!orig.isEmpty() && !(orig.length() == 1 && orig[0] == '.')) { + if (!result.isEmpty() && !result.endsWith('/')) + result.append('/'); + result.append(orig); + } + + if (result.length() == 1 && result[0] == '/') + return QFileSystemEntry(result, QFileSystemEntry::FromNativePath()); + const bool isDir = result.endsWith('/'); + + /* as long as QDir::cleanPath() operates on a QString we have to convert to a string here. + * ideally we never convert to a string since that loses information. Please fix after + * we get a QByteArray version of QDir::cleanPath() + */ + QFileSystemEntry resultingEntry(result, QFileSystemEntry::FromNativePath()); + QString stringVersion = QDir::cleanPath(resultingEntry.filePath()); + if (isDir) + stringVersion.append(QLatin1Char('/')); + return QFileSystemEntry(stringVersion); +} + +//static +QString QFileSystemEngine::resolveUserName(uint userId) +{ +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) + int size_max = sysconf(_SC_GETPW_R_SIZE_MAX); + if (size_max == -1) + size_max = 1024; + QVarLengthArray<char, 1024> buf(size_max); +#endif + + struct passwd *pw = 0; +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) + struct passwd entry; + getpwuid_r(userId, &entry, buf.data(), buf.size(), &pw); +#else + pw = getpwuid(userId); +#endif + if (pw) + return QFile::decodeName(QByteArray(pw->pw_name)); + return QString(); +} + +//static +QString QFileSystemEngine::resolveGroupName(uint groupId) +{ +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) + int size_max = sysconf(_SC_GETPW_R_SIZE_MAX); + if (size_max == -1) + size_max = 1024; + QVarLengthArray<char, 1024> buf(size_max); +#endif + + struct group *gr = 0; +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) + size_max = sysconf(_SC_GETGR_R_SIZE_MAX); + if (size_max == -1) + size_max = 1024; + buf.resize(size_max); + struct group entry; + // Some large systems have more members than the POSIX max size + // Loop over by doubling the buffer size (upper limit 250k) + for (unsigned size = size_max; size < 256000; size += size) + { + buf.resize(size); + // ERANGE indicates that the buffer was too small + if (!getgrgid_r(groupId, &entry, buf.data(), buf.size(), &gr) + || errno != ERANGE) + break; + } +#else + gr = getgrgid(groupId); +#endif + if (gr) + return QFile::decodeName(QByteArray(gr->gr_name)); + return QString(); +} + +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) +//static +QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry) +{ + QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(entry.filePath()), + kCFURLPOSIXPathStyle, true); + if (QCFType<CFDictionaryRef> dict = CFBundleCopyInfoDictionaryForURL(url)) { + if (CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) { + if (CFGetTypeID(name) == CFStringGetTypeID()) + return QCFString::toQString((CFStringRef)name); + } + } + return QString(); +} +#endif + +//static +bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, + QFileSystemMetaData::MetaDataFlags what) +{ +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) + if (what & QFileSystemMetaData::BundleType) { + if (!data.hasFlags(QFileSystemMetaData::DirectoryType)) + what |= QFileSystemMetaData::DirectoryType; + } +#endif + +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) \ + && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + if (what & QFileSystemMetaData::HiddenAttribute) { + // Mac OS >= 10.5: st_flags & UF_HIDDEN + what |= QFileSystemMetaData::PosixStatFlags; + } +#endif + + if (what & QFileSystemMetaData::PosixStatFlags) + what |= QFileSystemMetaData::PosixStatFlags; + + if (what & QFileSystemMetaData::ExistsAttribute) { + // FIXME: Would other queries being performed provide this bit? + what |= QFileSystemMetaData::PosixStatFlags; + } + + data.entryFlags &= ~what; + + const char * nativeFilePath; + int nativeFilePathLength; + { + const QByteArray &path = entry.nativeFilePath(); + nativeFilePath = path.constData(); + nativeFilePathLength = path.size(); + } + + bool entryExists = true; // innocent until proven otherwise + + QT_STATBUF statBuffer; + bool statBufferValid = false; + if (what & QFileSystemMetaData::LinkType) { + if (QT_LSTAT(nativeFilePath, &statBuffer) == 0) { + if (S_ISLNK(statBuffer.st_mode)) { + data.entryFlags |= QFileSystemMetaData::LinkType; + } else { + statBufferValid = true; + data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags; + } + } else { + entryExists = false; + } + + data.knownFlagsMask |= QFileSystemMetaData::LinkType; + } + + if (statBufferValid || (what & QFileSystemMetaData::PosixStatFlags)) { + if (entryExists && !statBufferValid) + statBufferValid = (QT_STAT(nativeFilePath, &statBuffer) == 0); + + if (statBufferValid) + data.fillFromStatBuf(statBuffer); + else { + entryExists = false; + data.creationTime_ = 0; + data.modificationTime_ = 0; + data.accessTime_ = 0; + data.size_ = 0; + data.userId_ = (uint) -2; + data.groupId_ = (uint) -2; + } + + // reset the mask + data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags + | QFileSystemMetaData::ExistsAttribute; + } + +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) + if (what & QFileSystemMetaData::AliasType) + { + if (entryExists) { + FSRef fref; + if (FSPathMakeRef((const UInt8 *)nativeFilePath, &fref, NULL) == noErr) { + Boolean isAlias, isFolder; + if (FSIsAliasFile(&fref, &isAlias, &isFolder) == noErr) { + if (isAlias) + data.entryFlags |= QFileSystemMetaData::AliasType; + } + } + } + data.knownFlagsMask |= QFileSystemMetaData::AliasType; + } +#endif + + if (what & QFileSystemMetaData::UserPermissions) { + // calculate user permissions + + if (entryExists) { + if (what & QFileSystemMetaData::UserReadPermission) { + if (QT_ACCESS(nativeFilePath, R_OK) == 0) + data.entryFlags |= QFileSystemMetaData::UserReadPermission; + } + if (what & QFileSystemMetaData::UserWritePermission) { + if (QT_ACCESS(nativeFilePath, W_OK) == 0) + data.entryFlags |= QFileSystemMetaData::UserWritePermission; + } + if (what & QFileSystemMetaData::UserExecutePermission) { + if (QT_ACCESS(nativeFilePath, X_OK) == 0) + data.entryFlags |= QFileSystemMetaData::UserExecutePermission; + } + } + data.knownFlagsMask |= (what & QFileSystemMetaData::UserPermissions); + } + + if (what & QFileSystemMetaData::HiddenAttribute + && !data.isHidden()) { + QString fileName = entry.fileName(); + if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.')) + || (entryExists && _q_isMacHidden(nativeFilePath))) + data.entryFlags |= QFileSystemMetaData::HiddenAttribute; + data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute; + } + +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) + if (what & QFileSystemMetaData::BundleType) { + if (entryExists && data.isDirectory()) { + QCFType<CFStringRef> path = CFStringCreateWithBytes(0, + (const UInt8*)nativeFilePath, nativeFilePathLength, + kCFStringEncodingUTF8, false); + QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, path, + kCFURLPOSIXPathStyle, true); + + UInt32 type, creator; + if (CFBundleGetPackageInfoInDirectory(url, &type, &creator)) + data.entryFlags |= QFileSystemMetaData::BundleType; + } + + data.knownFlagsMask |= QFileSystemMetaData::BundleType; + } +#endif + + return data.hasFlags(what); +} + +//static +bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents) +{ + QString dirName = entry.filePath(); + if (createParents) { + dirName = QDir::cleanPath(dirName); + for (int oldslash = -1, slash=0; slash != -1; oldslash = slash) { + slash = dirName.indexOf(QDir::separator(), oldslash+1); + if (slash == -1) { + if (oldslash == dirName.length()) + break; + slash = dirName.length(); + } + if (slash) { + QByteArray chunk = QFile::encodeName(dirName.left(slash)); + QT_STATBUF st; + if (QT_STAT(chunk, &st) != -1) { + if ((st.st_mode & S_IFMT) != S_IFDIR) + return false; + } else if (QT_MKDIR(chunk, 0777) != 0) { + return false; + } + } + } + return true; + } +#if defined(Q_OS_DARWIN) // Mac X doesn't support trailing /'s + if (dirName.endsWith(QLatin1Char('/'))) + dirName.chop(1); +#endif + return (QT_MKDIR(QFile::encodeName(dirName), 0777) == 0); +} + +//static +bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents) +{ + if (removeEmptyParents) { + QString dirName = QDir::cleanPath(entry.filePath()); + for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) { + QByteArray chunk = QFile::encodeName(dirName.left(slash)); + QT_STATBUF st; + if (QT_STAT(chunk, &st) != -1) { + if ((st.st_mode & S_IFMT) != S_IFDIR) + return false; + if (::rmdir(chunk) != 0) + return oldslash != 0; + } else { + return false; + } + slash = dirName.lastIndexOf(QDir::separator(), oldslash-1); + } + return true; + } + return rmdir(QFile::encodeName(entry.filePath())) == 0; +} + +//static +bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) +{ + if (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0) + return true; + error = QSystemError(errno, QSystemError::StandardLibraryError); + return false; +} + +//static +bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) +{ + Q_UNUSED(source); + Q_UNUSED(target); + // # we can implement this using sendfile(2) + //when this function returns false, block copy is used in QFile which sets the error code. + return false; +} + +//static +bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) +{ + if (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0) + return true; + error = QSystemError(errno, QSystemError::StandardLibraryError); + return false; +} + +//static +bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error) +{ + if (unlink(entry.nativeFilePath().constData()) == 0) + return true; + error = QSystemError(errno, QSystemError::StandardLibraryError); + return false; + +} + +//static +bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data) +{ + mode_t mode = 0; + if (permissions & QFile::ReadOwner) + mode |= S_IRUSR; + if (permissions & QFile::WriteOwner) + mode |= S_IWUSR; + if (permissions & QFile::ExeOwner) + mode |= S_IXUSR; + if (permissions & QFile::ReadUser) + mode |= S_IRUSR; + if (permissions & QFile::WriteUser) + mode |= S_IWUSR; + if (permissions & QFile::ExeUser) + mode |= S_IXUSR; + if (permissions & QFile::ReadGroup) + mode |= S_IRGRP; + if (permissions & QFile::WriteGroup) + mode |= S_IWGRP; + if (permissions & QFile::ExeGroup) + mode |= S_IXGRP; + if (permissions & QFile::ReadOther) + mode |= S_IROTH; + if (permissions & QFile::WriteOther) + mode |= S_IWOTH; + if (permissions & QFile::ExeOther) + mode |= S_IXOTH; + + bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0; + if (success && data) { + data->entryFlags &= ~QFileSystemMetaData::Permissions; + data->entryFlags |= QFileSystemMetaData::MetaDataFlag(uint(permissions)); + data->knownFlagsMask |= QFileSystemMetaData::Permissions; + } + if (!success) + error = QSystemError(errno, QSystemError::StandardLibraryError); + return success; +} + +QString QFileSystemEngine::homePath() +{ + QString home = QFile::decodeName(qgetenv("HOME")); + if (home.isNull()) + home = rootPath(); + return QDir::cleanPath(home); +} + +QString QFileSystemEngine::rootPath() +{ + return QLatin1String("/"); +} + +QString QFileSystemEngine::tempPath() +{ + QString temp = QFile::decodeName(qgetenv("TMPDIR")); + if (temp.isEmpty()) + temp = QLatin1String("/tmp/"); + return QDir::cleanPath(temp); +} + +bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &path) +{ + int r; + r = QT_CHDIR(path.nativeFilePath()); + return r >= 0; +} + +QFileSystemEntry QFileSystemEngine::currentPath() +{ + QFileSystemEntry result; + QT_STATBUF st; + if (QT_STAT(".", &st) == 0) { +#if defined(__GLIBC__) && !defined(PATH_MAX) + char *currentName = ::get_current_dir_name(); + if (currentName) { + result = QFile::decodeName(QByteArray(currentName)); + ::free(currentName); + } +#else + char currentName[PATH_MAX+1]; + if (::getcwd(currentName, PATH_MAX)) + result = QFileSystemEntry(QByteArray(currentName), QFileSystemEntry::FromNativePath()); +# if defined(QT_DEBUG) + if (result.isEmpty()) + qWarning("QFSFileEngine::currentPath: getcwd() failed"); +# endif +#endif + } else { +# if defined(QT_DEBUG) + qWarning("QFSFileEngine::currentPath: stat(\".\") failed"); +# endif + } + return result; +} +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp new file mode 100644 index 0000000..39fce97 --- /dev/null +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -0,0 +1,1211 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfilesystemengine_p.h" + +#define _POSIX_ +#include "qplatformdefs.h" +#include "qabstractfileengine.h" +#include "private/qfsfileengine_p.h" +#include <private/qsystemlibrary_p.h> +#include <qdebug.h> + +#include "qfile.h" +#include "qdir.h" +#include "private/qmutexpool_p.h" +#include "qvarlengtharray.h" +#include "qdatetime.h" +#include "qt_windows.h" + +#if !defined(Q_OS_WINCE) +# include <sys/types.h> +# include <direct.h> +# include <winioctl.h> +#else +# include <types.h> +#endif +#include <objbase.h> +#include <shlobj.h> +#include <initguid.h> +#include <accctrl.h> +#include <ctype.h> +#include <limits.h> +#define SECURITY_WIN32 +#include <security.h> + +#ifndef SPI_GETPLATFORMTYPE +#define SPI_GETPLATFORMTYPE 257 +#endif + +#ifndef PATH_MAX +#define PATH_MAX FILENAME_MAX +#endif + +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +#ifdef _W64 +typedef _W64 int intptr_t; +#else +typedef INT_PTR intptr_t; +#endif +#endif +#define _INTPTR_T_DEFINED +#endif + +#ifndef INVALID_FILE_ATTRIBUTES +# define INVALID_FILE_ATTRIBUTES (DWORD (-1)) +#endif + +#if !defined(Q_OS_WINCE) +# if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) +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) +# endif // !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) + +# ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE +# define MAXIMUM_REPARSE_DATA_BUFFER_SIZE 16384 +# endif +# ifndef IO_REPARSE_TAG_SYMLINK +# define IO_REPARSE_TAG_SYMLINK (0xA000000CL) +# endif +# ifndef FSCTL_GET_REPARSE_POINT +# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) +# endif +#endif // !defined(Q_OS_WINCE) + +QT_BEGIN_NAMESPACE + +Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0; + +#if defined(Q_OS_WINCE) +static QString qfsPrivateCurrentDir = QLatin1String(""); +// As none of the functions we try to resolve do exist on Windows CE +// we use QT_NO_LIBRARY to shorten everything up a little bit. +#define QT_NO_LIBRARY 1 +#endif + +#if !defined(QT_NO_LIBRARY) +QT_BEGIN_INCLUDE_NAMESPACE +typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); +static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0; +typedef BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE); +static PtrLookupAccountSidW ptrLookupAccountSidW = 0; +typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID); +static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0; +typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK); +static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0; +static TRUSTEE_W currentUserTrusteeW; +static TRUSTEE_W worldTrusteeW; + +typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD); +static PtrGetUserProfileDirectoryW ptrGetUserProfileDirectoryW = 0; +typedef BOOL (WINAPI *PtrGetVolumePathNamesForVolumeNameW)(LPCWSTR,LPWSTR,DWORD,PDWORD); +static PtrGetVolumePathNamesForVolumeNameW ptrGetVolumePathNamesForVolumeNameW = 0; +QT_END_INCLUDE_NAMESPACE + + +static void resolveLibs() +{ + 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; +#if !defined(Q_OS_WINCE) + HINSTANCE advapiHnd = QSystemLibrary::load(L"advapi32"); + if (advapiHnd) { + ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW"); + ptrLookupAccountSidW = (PtrLookupAccountSidW)GetProcAddress(advapiHnd, "LookupAccountSidW"); + ptrBuildTrusteeWithSidW = (PtrBuildTrusteeWithSidW)GetProcAddress(advapiHnd, "BuildTrusteeWithSidW"); + ptrGetEffectiveRightsFromAclW = (PtrGetEffectiveRightsFromAclW)GetProcAddress(advapiHnd, "GetEffectiveRightsFromAclW"); + } + if (ptrBuildTrusteeWithSidW) { + // Create TRUSTEE for current user + HANDLE hnd = ::GetCurrentProcess(); + HANDLE token = 0; + if (::OpenProcessToken(hnd, TOKEN_QUERY, &token)) { + TOKEN_USER tu; + DWORD retsize; + if (::GetTokenInformation(token, TokenUser, &tu, sizeof(tu), &retsize)) + ptrBuildTrusteeWithSidW(¤tUserTrusteeW, tu.User.Sid); + ::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) { + // 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); + } + } + HINSTANCE userenvHnd = QSystemLibrary::load(L"userenv"); + if (userenvHnd) + ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW"); + HINSTANCE kernel32 = LoadLibrary(L"kernel32"); + if(kernel32) + ptrGetVolumePathNamesForVolumeNameW = (PtrGetVolumePathNamesForVolumeNameW)GetProcAddress(kernel32, "GetVolumePathNamesForVolumeNameW"); +#endif + } +} +#endif // QT_NO_LIBRARY + +typedef DWORD (WINAPI *PtrNetShareEnum)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD); +static PtrNetShareEnum ptrNetShareEnum = 0; +typedef DWORD (WINAPI *PtrNetApiBufferFree)(LPVOID); +static PtrNetApiBufferFree ptrNetApiBufferFree = 0; +typedef struct _SHARE_INFO_1 { + LPWSTR shi1_netname; + DWORD shi1_type; + LPWSTR shi1_remark; +} SHARE_INFO_1; + + +static bool resolveUNCLibs() +{ + static bool triedResolve = false; + if (!triedResolve) { +#ifndef QT_NO_THREAD + QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); + if (triedResolve) { + return ptrNetShareEnum && ptrNetApiBufferFree; + } +#endif + triedResolve = true; +#if !defined(Q_OS_WINCE) + HINSTANCE hLib = QSystemLibrary::load(L"Netapi32"); + if (hLib) { + ptrNetShareEnum = (PtrNetShareEnum)GetProcAddress(hLib, "NetShareEnum"); + if (ptrNetShareEnum) + ptrNetApiBufferFree = (PtrNetApiBufferFree)GetProcAddress(hLib, "NetApiBufferFree"); + } +#endif + } + return ptrNetShareEnum && ptrNetApiBufferFree; +} + +static QString readSymLink(const QFileSystemEntry &link) +{ + QString result; +#if !defined(Q_OS_WINCE) + HANDLE handle = CreateFile((wchar_t*)link.nativeFilePath().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 if (rdb->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + 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); + +#if !defined(QT_NO_LIBRARY) + resolveLibs(); + if (ptrGetVolumePathNamesForVolumeNameW) { + QRegExp matchVolName(QLatin1String("^Volume\\{([a-z]|[0-9]|-)+\\}\\\\"), Qt::CaseInsensitive); + if(matchVolName.indexIn(result) == 0) { + DWORD len; + wchar_t buffer[MAX_PATH]; + QString volumeName = result.mid(0, matchVolName.matchedLength()).prepend(QLatin1String("\\\\?\\")); + if(ptrGetVolumePathNamesForVolumeNameW((wchar_t*)volumeName.utf16(), buffer, MAX_PATH, &len) != 0) + result.replace(0,matchVolName.matchedLength(), QString::fromWCharArray(buffer)); + } + } +#endif + } +#else + Q_UNUSED(link); +#endif // Q_OS_WINCE + return result; +} + +static QString readLink(const QFileSystemEntry &link) +{ +#if !defined(Q_OS_WINCE) +#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS) + QString ret; + + bool neededCoInit = false; + IShellLink *psl; // pointer to IShellLink i/f + WIN32_FIND_DATA wfd; + wchar_t szGotPath[MAX_PATH]; + + // Get pointer to the IShellLink interface. + HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl); + + if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized + neededCoInit = true; + CoInitialize(NULL); + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLink, (LPVOID *)&psl); + } + if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface. + IPersistFile *ppf; + hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); + if (SUCCEEDED(hres)) { + hres = ppf->Load((LPOLESTR)link.nativeFilePath().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 (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR) + ret = QString::fromWCharArray(szGotPath); + } + ppf->Release(); + } + psl->Release(); + } + if (neededCoInit) + CoUninitialize(); + + return ret; +#else + Q_UNUSED(link); + return QString(); +#endif // QT_NO_LIBRARY +#else + wchar_t target[MAX_PATH]; + QString result; + if (SHGetShortcutTarget((wchar_t*)QFileInfo(link.filePath()).absoluteFilePath().replace(QLatin1Char('/'),QLatin1Char('\\')).utf16(), target, MAX_PATH)) { + result = QString::fromWCharArray(target); + if (result.startsWith(QLatin1Char('"'))) + result.remove(0,1); + if (result.endsWith(QLatin1Char('"'))) + result.remove(result.size()-1,1); + } + return result; +#endif // Q_OS_WINCE +} + +static bool uncShareExists(const QString &server) +{ + // This code assumes the UNC path is always like \\?\UNC\server... + QStringList parts = server.split(QLatin1Char('\\'), QString::SkipEmptyParts); + if (parts.count() >= 3) { + QStringList shares; + if (QFileSystemEngine::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(2), &shares)) + return parts.count() >= 4 ? shares.contains(parts.at(3), Qt::CaseInsensitive) : true; + } + return false; +} + +static inline bool getFindData(QString path, WIN32_FIND_DATA &findData) +{ + // path should not end with a trailing slash + while (path.endsWith(QLatin1Char('\\'))) + path.chop(1); + + // can't handle drives + if (!path.endsWith(QLatin1Char(':'))) { + HANDLE hFind = ::FindFirstFile((wchar_t*)path.utf16(), &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + return true; + } + } + + return false; +} + +bool QFileSystemEngine::uncListSharesOnServer(const QString &server, QStringList *list) +{ + if (resolveUNCLibs()) { + SHARE_INFO_1 *BufPtr, *p; + DWORD res; + 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) { + p = BufPtr; + for (i = 1; i <= er; ++i) { + if (list && p->shi1_type == 0) + list->append(QString::fromWCharArray(p->shi1_netname)); + p++; + } + } + ptrNetApiBufferFree(BufPtr); + } while (res == ERROR_MORE_DATA); + return res == ERROR_SUCCESS; + } + return false; +} + +void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data) +{ + data.size_ = 0; + data.fileAttribute_ = 0; +} + +bool QFileSystemEngine::isCaseSensitive() +{ + return false; +} + +//static +QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, + QFileSystemMetaData &data) +{ + if (data.missingFlags(QFileSystemMetaData::LinkType)) + QFileSystemEngine::fillMetaData(link, data, QFileSystemMetaData::LinkType); + + QString ret; + if (data.isLnkFile()) + ret = readLink(link); + else if (data.isLink()) + ret = readSymLink(link); + return QFileSystemEntry(ret); +} + +//static +QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data) +{ + if (data.missingFlags(QFileSystemMetaData::ExistsAttribute)) + QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute); + + if (data.exists()) + return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath())); + else + return QFileSystemEntry(); +} + +//static +QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path) +{ + // can be //server or //server/share + QString absPath; +#if !defined(Q_OS_WINCE) + QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1)); + wchar_t *fileName = 0; + DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName); + if (retLen > (DWORD)buf.size()) { + buf.resize(retLen); + retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName); + } + if (retLen != 0) + absPath = QString::fromWCharArray(buf.data(), retLen); +#else + if (path.startsWith(QLatin1Char('/')) || path.startsWith(QLatin1Char('\\'))) + absPath = QDir::toNativeSeparators(path); + else + absPath = QDir::toNativeSeparators(QDir::cleanPath(qfsPrivateCurrentDir + QLatin1Char('/') + path)); +#endif + // This is really ugly, but GetFullPathName strips off whitespace at the end. + // If you for instance write ". " in the lineedit of QFileDialog, + // (which is an invalid filename) this function will strip the space off and viola, + // the file is later reported as existing. Therefore, we re-add the whitespace that + // was at the end of path in order to keep the filename invalid. + if (!path.isEmpty() && path.at(path.size() - 1) == QLatin1Char(' ')) + absPath.append(QLatin1Char(' ')); + return absPath; +} + +//static +QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry) +{ + QString ret; + + if (!entry.isRelative()) { +#if !defined(Q_OS_WINCE) + if (entry.isAbsolute() + && !entry.filePath().contains(QLatin1String("/../")) + && !entry.filePath().contains(QLatin1String("/./")) + && !entry.filePath().endsWith(QLatin1String("/..")) + && !entry.filePath().endsWith(QLatin1String("/."))) { + ret = entry.filePath(); + } else { + ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(entry.filePath())); + } +#else + ret = entry.filePath(); +#endif + } else { + ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + entry.filePath()); + } + + // The path should be absolute at this point. + // From the docs : + // Absolute paths begin with the directory separator "/" + // (optionally preceded by a drive specification under Windows). + if (ret.at(0) != QLatin1Char('/')) { + Q_ASSERT(ret.length() >= 2); + Q_ASSERT(ret.at(0).isLetter()); + Q_ASSERT(ret.at(1) == QLatin1Char(':')); + + // Force uppercase drive letters. + ret[0] = ret.at(0).toUpper(); + } + return QFileSystemEntry(ret); +} + +//static +QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own) +{ + QString name; +#if !defined(QT_NO_LIBRARY) + extern int qt_ntfs_permission_lookup; + if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) { + resolveLibs(); + if (ptrGetNamedSecurityInfoW && ptrLookupAccountSidW) { + PSID pOwner = 0; + PSECURITY_DESCRIPTOR pSD; + if (ptrGetNamedSecurityInfoW((wchar_t*)entry.nativeFilePath().utf16(), SE_FILE_OBJECT, + own == QAbstractFileEngine::OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION, + own == QAbstractFileEngine::OwnerUser ? &pOwner : 0, own == QAbstractFileEngine::OwnerGroup ? &pOwner : 0, + 0, 0, &pSD) == ERROR_SUCCESS) { + DWORD lowner = 64; + DWORD ldomain = 64; + QVarLengthArray<wchar_t, 64> owner(lowner); + QVarLengthArray<wchar_t, 64> domain(ldomain); + SID_NAME_USE use = SidTypeUnknown; + // First call, to determine size of the strings (with '\0'). + if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner, + (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + if (lowner > (DWORD)owner.size()) + owner.resize(lowner); + if (ldomain > (DWORD)domain.size()) + domain.resize(ldomain); + // Second call, try on resized buf-s + if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner, + (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) { + lowner = 0; + } + } else { + lowner = 0; + } + } + if (lowner != 0) + name = QString::fromWCharArray(owner.data()); + LocalFree(pSD); + } + } + } +#else + Q_UNUSED(own); +#endif + return name; +} + +//static +bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSystemMetaData &data, + QFileSystemMetaData::MetaDataFlags what) +{ + QAbstractFileEngine::FileFlags ret = 0; + +#if !defined(QT_NO_LIBRARY) + if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) { + resolveLibs(); + if(ptrGetNamedSecurityInfoW && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW) { + enum { ReadMask = 0x00000001, WriteMask = 0x00000002, ExecMask = 0x00000020 }; + + QString fname = entry.filePath(); + PSID pOwner = 0; + PSID pGroup = 0; + PACL pDacl; + PSECURITY_DESCRIPTOR pSD; + DWORD res = ptrGetNamedSecurityInfoW((wchar_t*)fname.utf16(), SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + &pOwner, &pGroup, &pDacl, 0, &pSD); + if(res == ERROR_SUCCESS) { + ACCESS_MASK access_mask; + TRUSTEE_W trustee; + if (what & QFileSystemMetaData::UserPermissions) { // user + data.knownFlagsMask |= QFileSystemMetaData::UserPermissions; + if(ptrGetEffectiveRightsFromAclW(pDacl, ¤tUserTrusteeW, &access_mask) != ERROR_SUCCESS) + access_mask = (ACCESS_MASK)-1; + if(access_mask & ReadMask) + data.entryFlags |= QFileSystemMetaData::UserReadPermission; + if(access_mask & WriteMask) + data.entryFlags|= QFileSystemMetaData::UserWritePermission; + if(access_mask & ExecMask) + data.entryFlags|= QFileSystemMetaData::UserExecutePermission; + } + if (what & QFileSystemMetaData::OwnerPermissions) { // owner + data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions; + ptrBuildTrusteeWithSidW(&trustee, pOwner); + if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) + access_mask = (ACCESS_MASK)-1; + if(access_mask & ReadMask) + data.entryFlags |= QFileSystemMetaData::OwnerReadPermission; + if(access_mask & WriteMask) + data.entryFlags |= QFileSystemMetaData::OwnerWritePermission; + if(access_mask & ExecMask) + data.entryFlags |= QFileSystemMetaData::OwnerExecutePermission; + } + if (what & QFileSystemMetaData::GroupPermissions) { // group + data.knownFlagsMask |= QFileSystemMetaData::GroupPermissions; + ptrBuildTrusteeWithSidW(&trustee, pGroup); + if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) + access_mask = (ACCESS_MASK)-1; + if(access_mask & ReadMask) + data.entryFlags |= QFileSystemMetaData::GroupReadPermission; + if(access_mask & WriteMask) + data.entryFlags |= QFileSystemMetaData::GroupWritePermission; + if(access_mask & ExecMask) + data.entryFlags |= QFileSystemMetaData::GroupExecutePermission; + } + if (what & QFileSystemMetaData::OtherPermissions) { // other (world) + data.knownFlagsMask |= QFileSystemMetaData::OtherPermissions; + if(ptrGetEffectiveRightsFromAclW(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS) + access_mask = (ACCESS_MASK)-1; // ### + if(access_mask & ReadMask) + data.entryFlags |= QFileSystemMetaData::OtherReadPermission; + if(access_mask & WriteMask) + data.entryFlags |= QFileSystemMetaData::OtherWritePermission; + if(access_mask & ExecMask) + data.entryFlags |= QFileSystemMetaData::OwnerExecutePermission; + } + LocalFree(pSD); + } + } + } else +#endif + { + //### what to do with permissions if we don't use NTFS + // for now just add all permissions and what about exe missions ?? + // also qt_ntfs_permission_lookup is now not set by default ... should it ? + data.entryFlags |= QFileSystemMetaData::OwnerReadPermission + | QFileSystemMetaData::GroupReadPermission + | QFileSystemMetaData::OtherReadPermission; + + if (!(data.fileAttribute_ & FILE_ATTRIBUTE_READONLY)) { + data.entryFlags |= QFileSystemMetaData::OwnerWritePermission + | QFileSystemMetaData::GroupWritePermission + | QFileSystemMetaData::OtherWritePermission; + } + + QString fname = entry.filePath(); + QString ext = fname.right(4).toLower(); + if (data.isDirectory() || + ext == QLatin1String(".exe") || ext == QLatin1String(".com") || ext == QLatin1String(".bat") || + ext == QLatin1String(".pif") || ext == QLatin1String(".cmd")) { + data.entryFlags |= QFileSystemMetaData::OwnerExecutePermission | QFileSystemMetaData::GroupExecutePermission + | QFileSystemMetaData::OtherExecutePermission | QFileSystemMetaData::UserExecutePermission; + } + data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions | QFileSystemMetaData::GroupPermissions + | QFileSystemMetaData::OtherPermissions | QFileSystemMetaData::UserExecutePermission; + // calculate user permissions + if (what & QFileSystemMetaData::UserReadPermission) { + if (::_waccess((wchar_t*)entry.nativeFilePath().utf16(), R_OK) == 0) + data.entryFlags |= QFileSystemMetaData::UserReadPermission; + data.knownFlagsMask |= QFileSystemMetaData::UserReadPermission; + } + if (what & QFileSystemMetaData::UserWritePermission) { + if (::_waccess((wchar_t*)entry.nativeFilePath().utf16(), W_OK) == 0) + data.entryFlags |= QFileSystemMetaData::UserWritePermission; + data.knownFlagsMask |= QFileSystemMetaData::UserReadPermission; + } + } + + return data.hasFlags(what); +} + +static bool tryDriveUNCFallback(const QFileSystemEntry &fname, QFileSystemMetaData &data) +{ + bool entryExists = false; + DWORD fileAttrib = 0; +#if !defined(Q_OS_WINCE) + if (fname.isDriveRoot()) { + // a valid drive ?? + DWORD drivesBitmask = ::GetLogicalDrives(); + int drivebit = 1 << (fname.filePath().at(0).toUpper().unicode() - QLatin1Char('A').unicode()); + if (drivesBitmask & drivebit) { + fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM; + entryExists = true; + } + } else { +#endif + const QString &path = fname.nativeFilePath(); + bool is_dir = false; + if (path.startsWith(QLatin1String("\\\\?\\UNC"))) { + // UNC - stat doesn't work for all cases (Windows bug) + int s = path.indexOf(path.at(0),7); + if (s > 0) { + // "\\?\UNC\server\..." + s = path.indexOf(path.at(0),s+1); + if (s > 0) { + // "\\?\UNC\server\share\..." + if (s == path.size() - 1) { + // "\\?\UNC\server\share\" + is_dir = true; + } else { + // "\\?\UNC\server\share\notfound" + } + } else { + // "\\?\UNC\server\share" + is_dir = true; + } + } else { + // "\\?\UNC\server" + is_dir = true; + } + } + if (is_dir && uncShareExists(path)) { + // looks like a UNC dir, is a dir. + fileAttrib = FILE_ATTRIBUTE_DIRECTORY; + entryExists = true; + } +#if !defined(Q_OS_WINCE) + } +#endif + if (entryExists) + data.fillFromFileAttribute(fileAttrib); + return entryExists; +} + +static bool tryFindFallback(const QFileSystemEntry &fname, QFileSystemMetaData &data) +{ + bool filledData = false; + // This assumes the last call to a Windows API failed. + int errorCode = GetLastError(); + if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { + WIN32_FIND_DATA findData; + if (getFindData(fname.nativeFilePath(), findData) + && findData.dwFileAttributes != INVALID_FILE_ATTRIBUTES) { + data.fillFromFindData(findData, true, fname.isDriveRoot()); + filledData = true; + } + } + return filledData; +} + +#if !defined(Q_OS_WINCE) +//static +bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data, + QFileSystemMetaData::MetaDataFlags what) +{ + HANDLE fHandle = (HANDLE)_get_osfhandle(fd); + if (fHandle != INVALID_HANDLE_VALUE) { + return fillMetaData(fHandle, data, what); + } + return false; +} +#endif + +//static +bool QFileSystemEngine::fillMetaData(HANDLE fHandle, QFileSystemMetaData &data, + QFileSystemMetaData::MetaDataFlags what) +{ + data.entryFlags &= ~what; + clearWinStatData(data); + BY_HANDLE_FILE_INFORMATION fileInfo; + UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + if (GetFileInformationByHandle(fHandle , &fileInfo)) { + data.fillFromFindInfo(fileInfo); + } + SetErrorMode(oldmode); + return data.hasFlags(what); +} + +//static +bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, + QFileSystemMetaData::MetaDataFlags what) +{ + what |= QFileSystemMetaData::WinLnkType | QFileSystemMetaData::WinStatFlags; + data.entryFlags &= ~what; + + QFileSystemEntry fname; + data.knownFlagsMask |= QFileSystemMetaData::WinLnkType; + if(entry.filePath().endsWith(QLatin1String(".lnk"))) { + data.entryFlags |= QFileSystemMetaData::WinLnkType; + fname = QFileSystemEntry(readLink(entry)); + } else { + fname = entry; + } + + if (fname.isEmpty()) { + data.knownFlagsMask |= what; + clearWinStatData(data); + return false; + } + + if (what & QFileSystemMetaData::WinStatFlags) { + UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + clearWinStatData(data); + WIN32_FIND_DATA findData; + // The memory structure for WIN32_FIND_DATA is same as WIN32_FILE_ATTRIBUTE_DATA + // for all members used by fillFindData(). + bool ok = ::GetFileAttributesEx((wchar_t*)fname.nativeFilePath().utf16(), GetFileExInfoStandard, + reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA *>(&findData)); + if (ok) { + data.fillFromFindData(findData, false, fname.isDriveRoot()); + } else { + if (!tryFindFallback(fname, data)) + tryDriveUNCFallback(fname, data); + } + SetErrorMode(oldmode); + } + + if (what & QFileSystemMetaData::Permissions) + fillPermissions(fname, data, what); + if ((what & QFileSystemMetaData::LinkType) + && data.missingFlags(QFileSystemMetaData::LinkType)) { + data.knownFlagsMask |= QFileSystemMetaData::LinkType; + if (data.fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATA findData; + if (getFindData(fname.nativeFilePath(), findData)) + data.fillFromFindData(findData, true); + } + } + data.knownFlagsMask |= what; + return data.hasFlags(what); +} + +static inline bool mkDir(const QString &path) +{ +#if defined(Q_OS_WINCE) + // Unfortunately CreateDirectory returns true for paths longer than + // 256, but does not create a directory. It starts to fail, when + // path length > MAX_PATH, which is 260 usually on CE. + // This only happens on a Windows Mobile device. Windows CE seems + // not to be affected by this. + static int platformId = 0; + if (platformId == 0) { + wchar_t platformString[64]; + if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(platformString)/sizeof(*platformString),platformString,0)) { + if (0 == wcscmp(platformString, L"PocketPC") || 0 == wcscmp(platformString, L"Smartphone")) + platformId = 1; + else + platformId = 2; + } + } + if (platformId == 1 && QFSFileEnginePrivate::longFileName(path).size() > 256) + return false; +#endif + return ::CreateDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), 0); +} + +static inline bool rmDir(const QString &path) +{ + return ::RemoveDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); +} + +static bool isDirPath(const QString &dirPath, bool *existed) +{ + QString path = dirPath; + if (path.length() == 2 && path.at(1) == QLatin1Char(':')) + path += QLatin1Char('\\'); + + DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); + if (fileAttrib == INVALID_FILE_ATTRIBUTES) { + int errorCode = GetLastError(); + if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { + WIN32_FIND_DATA findData; + if (getFindData(QFSFileEnginePrivate::longFileName(path), findData)) + fileAttrib = findData.dwFileAttributes; + } + } + + if (existed) + *existed = fileAttrib != INVALID_FILE_ATTRIBUTES; + + if (fileAttrib == INVALID_FILE_ATTRIBUTES) + return false; + + return fileAttrib & FILE_ATTRIBUTE_DIRECTORY; +} + +//static +bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents) +{ + QString dirName = entry.filePath(); + if (createParents) { + dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); + // We spefically search for / so \ would break it.. + int oldslash = -1; + if (dirName.startsWith(QLatin1String("\\\\"))) { + // Don't try to create the root path of a UNC path; + // CreateDirectory() will just return ERROR_INVALID_NAME. + for (int i = 0; i < dirName.size(); ++i) { + if (dirName.at(i) != QDir::separator()) { + oldslash = i; + break; + } + } + if (oldslash != -1) + oldslash = dirName.indexOf(QDir::separator(), oldslash); + } + for (int slash=0; slash != -1; oldslash = slash) { + slash = dirName.indexOf(QDir::separator(), oldslash+1); + if (slash == -1) { + if (oldslash == dirName.length()) + break; + slash = dirName.length(); + } + if (slash) { + QString chunk = dirName.left(slash); + bool existed = false; + if (!isDirPath(chunk, &existed)) { + if (!existed) { + if (!mkDir(chunk)) + return false; + } else { + return false; + } + } + } + } + return true; + } + return mkDir(entry.filePath()); +} + +//static +bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents) +{ + QString dirName = entry.filePath(); + if (removeEmptyParents) { + dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); + for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) { + QString chunk = dirName.left(slash); + if (chunk.length() == 2 && chunk.at(0).isLetter() && chunk.at(1) == QLatin1Char(':')) + break; + if (!isDirPath(chunk, 0)) + return false; + if (!rmDir(chunk)) + return oldslash != 0; + slash = dirName.lastIndexOf(QDir::separator(), oldslash-1); + } + return true; + } + return rmDir(entry.filePath()); +} + +//static +QString QFileSystemEngine::rootPath() +{ +#if defined(Q_OS_WINCE) + QString ret = QLatin1String("/"); +#elif defined(Q_FS_FAT) + QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData()); + if (ret.isEmpty()) + ret = QLatin1String("c:"); + ret.append(QLatin1Char('/')); +#elif defined(Q_OS_OS2EMX) + char dir[4]; + _abspath(dir, QLatin1String("/"), _MAX_PATH); + QString ret(dir); +#endif + return ret; +} + +//static +QString QFileSystemEngine::homePath() +{ + QString ret; +#if !defined(QT_NO_LIBRARY) + resolveLibs(); + if (ptrGetUserProfileDirectoryW) { + HANDLE hnd = ::GetCurrentProcess(); + HANDLE token = 0; + BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token); + if (ok) { + DWORD dwBufferSize = 0; + // First call, to determine size of the strings (with '\0'). + ok = ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize); + if (!ok && dwBufferSize != 0) { // We got the required buffer size + wchar_t *userDirectory = new wchar_t[dwBufferSize]; + // Second call, now we can fill the allocated buffer. + ok = ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize); + if (ok) + ret = QString::fromWCharArray(userDirectory); + delete [] userDirectory; + } + ::CloseHandle(token); + } + } +#endif + if (ret.isEmpty() || !QFile::exists(ret)) { + ret = QString::fromLocal8Bit(qgetenv("USERPROFILE").constData()); + if (ret.isEmpty() || !QFile::exists(ret)) { + ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE").constData()) + + QString::fromLocal8Bit(qgetenv("HOMEPATH").constData()); + if (ret.isEmpty() || !QFile::exists(ret)) { + ret = QString::fromLocal8Bit(qgetenv("HOME").constData()); + if (ret.isEmpty() || !QFile::exists(ret)) { +#if defined(Q_OS_WINCE) + ret = QLatin1String("\\My Documents"); + if (!QFile::exists(ret)) +#endif + ret = rootPath(); + } + } + } + } + return QDir::fromNativeSeparators(ret); +} + +QString QFileSystemEngine::tempPath() +{ + QString ret; + wchar_t tempPath[MAX_PATH]; + DWORD len = GetTempPath(MAX_PATH, tempPath); + if (len) + ret = QString::fromWCharArray(tempPath, len); + if (!ret.isEmpty()) { + while (ret.endsWith(QLatin1Char('\\'))) + ret.chop(1); + ret = QDir::fromNativeSeparators(ret); + } + if (ret.isEmpty()) { +#if !defined(Q_OS_WINCE) + ret = QLatin1String("c:/tmp"); +#else + ret = QLatin1String("/Temp"); +#endif + } + return ret; +} + +bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry) +{ + QFileSystemMetaData meta; + fillMetaData(entry, meta, QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType); + if(!(meta.exists() && meta.isDirectory())) + return false; + +#if !defined(Q_OS_WINCE) + //TODO: this should really be using nativeFilePath(), but that returns a path in long format \\?\c:\foo + //which causes many problems later on when it's returned through currentPath() + return ::SetCurrentDirectory(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(entry.filePath()).utf16())) != 0; +#else + qfsPrivateCurrentDir = entry.filePath(); + return true; +#endif +} + +QFileSystemEntry QFileSystemEngine::currentPath() +{ + QString ret; +#if !defined(Q_OS_WINCE) + DWORD size = 0; + wchar_t currentName[PATH_MAX]; + size = ::GetCurrentDirectory(PATH_MAX, currentName); + if (size != 0) { + if (size > PATH_MAX) { + wchar_t *newCurrentName = new wchar_t[size]; + if (::GetCurrentDirectory(PATH_MAX, newCurrentName) != 0) + ret = QString::fromWCharArray(newCurrentName, size); + delete [] newCurrentName; + } else { + ret = QString::fromWCharArray(currentName, size); + } + } + if (ret.length() >= 2 && ret[1] == QLatin1Char(':')) + ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters. +#else + Q_UNUSED(fileName); + //TODO - a race condition exists when using currentPath / setCurrentPath from multiple threads + if (qfsPrivateCurrentDir.isEmpty()) + qfsPrivateCurrentDir = QCoreApplication::applicationDirPath(); + + ret = qfsPrivateCurrentDir; +#endif + return QFileSystemEntry(ret, QFileSystemEntry::FromNativePath()); +} + +//static +bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) +{ + Q_ASSERT(false); + return false; // TODO implement; - code needs to be moved from qfsfileengine_win.cpp +} + +//static +bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) +{ + bool ret = ::CopyFile((wchar_t*)source.nativeFilePath().utf16(), + (wchar_t*)target.nativeFilePath().utf16(), true) != 0; + if(!ret) + error = QSystemError(::GetLastError(), QSystemError::NativeError); + return ret; +} + +//static +bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) +{ + bool ret = ::MoveFile((wchar_t*)source.nativeFilePath().utf16(), + (wchar_t*)target.nativeFilePath().utf16()) != 0; + if(!ret) + error = QSystemError(::GetLastError(), QSystemError::NativeError); + return ret; +} + +//static +bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error) +{ + bool ret = ::DeleteFile((wchar_t*)entry.nativeFilePath().utf16()) != 0; + if(!ret) + error = QSystemError(::GetLastError(), QSystemError::NativeError); + return ret; +} + +//static +bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, + QFileSystemMetaData *data) +{ + Q_UNUSED(data); + int mode = 0; + + if (permissions & QFile::ReadOwner || permissions & QFile::ReadUser + || permissions & QFile::ReadGroup || permissions & QFile::ReadOther) + mode |= _S_IREAD; + if (permissions & QFile::WriteOwner || permissions & QFile::WriteUser + || permissions & QFile::WriteGroup || permissions & QFile::WriteOther) + mode |= _S_IWRITE; + + if (mode == 0) // not supported + return false; + + bool ret = (::_wchmod((wchar_t*)entry.nativeFilePath().utf16(), mode) == 0); + if(!ret) + error = QSystemError(errno, QSystemError::StandardLibraryError); + return ret; +} + +static inline QDateTime fileTimeToQDateTime(const FILETIME *time) +{ + QDateTime ret; + +#if defined(Q_OS_WINCE) + SYSTEMTIME systime; + FILETIME ftime; + systime.wYear = 1970; + systime.wMonth = 1; + systime.wDay = 1; + systime.wHour = 0; + systime.wMinute = 0; + systime.wSecond = 0; + systime.wMilliseconds = 0; + systime.wDayOfWeek = 4; + SystemTimeToFileTime(&systime, &ftime); + unsigned __int64 acttime = (unsigned __int64)time->dwHighDateTime << 32 | time->dwLowDateTime; + FileTimeToSystemTime(time, &systime); + unsigned __int64 time1970 = (unsigned __int64)ftime.dwHighDateTime << 32 | ftime.dwLowDateTime; + unsigned __int64 difftime = acttime - time1970; + difftime /= 10000000; + ret.setTime_t((unsigned int)difftime); +#else + SYSTEMTIME sTime, lTime; + FileTimeToSystemTime(time, &sTime); + SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime); + ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay)); + ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds)); +#endif + + return ret; +} + +QDateTime QFileSystemMetaData::creationTime() const +{ + return fileTimeToQDateTime(&creationTime_); +} +QDateTime QFileSystemMetaData::modificationTime() const +{ + return fileTimeToQDateTime(&lastWriteTime_); +} +QDateTime QFileSystemMetaData::accessTime() const +{ + return fileTimeToQDateTime(&lastAccessTime_); +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp new file mode 100644 index 0000000..d4c6d0a --- /dev/null +++ b/src/corelib/io/qfilesystementry.cpp @@ -0,0 +1,383 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfilesystementry_p.h" + +#include <QtCore/qdir.h> +#include <QtCore/qfile.h> +#include <QtCore/private/qfsfileengine_p.h> +#ifdef Q_OS_WIN +#include <QtCore/qstringbuilder.h> +#endif + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN +static bool isUncRoot(const QString &server) +{ + QString localPath = QDir::toNativeSeparators(server); + if (!localPath.startsWith(QLatin1String("\\\\"))) + return false; + + int idx = localPath.indexOf(QLatin1Char('\\'), 2); + if (idx == -1 || idx + 1 == localPath.length()) + return true; + + localPath = localPath.right(localPath.length() - idx - 1).trimmed(); + return localPath.isEmpty(); +} + +static inline QString fixIfRelativeUncPath(const QString &path) +{ + QString currentPath = QDir::currentPath(); + if (currentPath.startsWith(QLatin1String("//"))) + return currentPath % QChar(QLatin1Char('/')) % path; + return path; +} +#endif + +QFileSystemEntry::QFileSystemEntry() + : m_lastSeparator(0), + m_firstDotInFileName(0), + m_lastDotInFileName(0) +{ +} + +/*! + \internal + Use this constructor when the path is supplied by user code, as it may contain a mix + of '/' and the native separator. + */ +QFileSystemEntry::QFileSystemEntry(const QString &filePath) + : m_filePath(QDir::fromNativeSeparators(filePath)), + m_lastSeparator(-2), + m_firstDotInFileName(-2), + m_lastDotInFileName(0) +{ +} + +/*! + \internal + Use this constructor when the path is guaranteed to be in internal format, i.e. all + directory separators are '/' and not the native separator. + */ +QFileSystemEntry::QFileSystemEntry(const QString &filePath, FromInternalPath /* dummy */) + : m_filePath(filePath), + m_lastSeparator(-2), + m_firstDotInFileName(-2), + m_lastDotInFileName(0) +{ +} + +/*! + \internal + Use this constructor when the path comes from a native API + */ +QFileSystemEntry::QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath /* dummy */) + : m_nativeFilePath(nativeFilePath), + m_lastSeparator(-2), + m_firstDotInFileName(-2), + m_lastDotInFileName(0) +{ +} + +QFileSystemEntry::QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath) + : m_filePath(QDir::fromNativeSeparators(filePath)), + m_nativeFilePath(nativeFilePath), + m_lastSeparator(-2), + m_firstDotInFileName(-2), + m_lastDotInFileName(0) +{ +} + +QString QFileSystemEntry::filePath() const +{ + resolveFilePath(); + return m_filePath; +} + +QFileSystemEntry::NativePath QFileSystemEntry::nativeFilePath() const +{ + resolveNativeFilePath(); + return m_nativeFilePath; +} + +void QFileSystemEntry::resolveFilePath() const +{ + if (m_filePath.isEmpty() && !m_nativeFilePath.isEmpty()) { +#if defined(QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16) + m_filePath = QDir::fromNativeSeparators(m_nativeFilePath); +#ifdef Q_OS_WIN + if (m_filePath.startsWith(QLatin1String("//?/UNC/"))) + m_filePath = m_filePath.remove(2,6); + if (m_filePath.startsWith(QLatin1String("//?/"))) + m_filePath = m_filePath.remove(0,4); +#endif +#else + m_filePath = QDir::fromNativeSeparators(QFile::decodeName(m_nativeFilePath)); +#endif + } +} + +void QFileSystemEntry::resolveNativeFilePath() const +{ + if (!m_filePath.isEmpty() && m_nativeFilePath.isEmpty()) { +#ifdef Q_OS_WIN + QString filePath = m_filePath; + if (isRelative()) + filePath = fixIfRelativeUncPath(m_filePath); + m_nativeFilePath = QFSFileEnginePrivate::longFileName(QDir::toNativeSeparators(filePath)); +#elif defined(QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16) + m_nativeFilePath = QDir::toNativeSeparators(m_filePath); +#else + m_nativeFilePath = QFile::encodeName(QDir::toNativeSeparators(m_filePath)); +#endif + } +} + +QString QFileSystemEntry::fileName() const +{ + findLastSeparator(); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':')) + return m_filePath.mid(2); +#endif + return m_filePath.mid(m_lastSeparator + 1); +} + +QString QFileSystemEntry::path() const +{ + findLastSeparator(); + if (m_lastSeparator == -1) { +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + if (m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':')) + return m_filePath.left(2); +#endif + return QString(QLatin1Char('.')); + } + if (m_lastSeparator == 0) + return QString(QLatin1Char('/')); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + if (m_lastSeparator == 2 && m_filePath.at(1) == QLatin1Char(':')) + return m_filePath.left(m_lastSeparator + 1); +#endif + return m_filePath.left(m_lastSeparator); +} + +QString QFileSystemEntry::baseName() const +{ + findFileNameSeparators(); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':')) + return m_filePath.mid(2); +#endif + int length = -1; + if (m_firstDotInFileName >= 0) { + length = m_firstDotInFileName; + if (m_lastSeparator != -1) // avoid off by one + length--; + } + return m_filePath.mid(m_lastSeparator + 1, length); +} + +QString QFileSystemEntry::completeBaseName() const +{ + findFileNameSeparators(); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':')) + return m_filePath.mid(2); +#endif + int length = -1; + if (m_firstDotInFileName >= 0) { + length = m_firstDotInFileName + m_lastDotInFileName; + if (m_lastSeparator != -1) // avoid off by one + length--; + } + return m_filePath.mid(m_lastSeparator + 1, length); +} + +QString QFileSystemEntry::suffix() const +{ + findFileNameSeparators(); + + if (m_lastDotInFileName == -1) + return QString(); + + return m_filePath.mid(qMax((qint16)0, m_lastSeparator) + m_firstDotInFileName + m_lastDotInFileName + 1); +} + +QString QFileSystemEntry::completeSuffix() const +{ + findFileNameSeparators(); + if (m_firstDotInFileName == -1) + return QString(); + + return m_filePath.mid(qMax((qint16)0, m_lastSeparator) + m_firstDotInFileName + 1); +} + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +bool QFileSystemEntry::isRelative() const +{ + resolveFilePath(); + return (m_filePath.isEmpty() || (!m_filePath.isEmpty() && (m_filePath[0].unicode() != '/') + && (!(m_filePath.length() >= 2 && m_filePath[1].unicode() == ':')))); +} + +bool QFileSystemEntry::isAbsolute() const +{ + resolveFilePath(); + return (!m_filePath.isEmpty() && ((m_filePath.length() >= 3 + && (m_filePath[0].isLetter() && m_filePath[1].unicode() == ':' && m_filePath[2].unicode() == '/')) +#ifdef Q_OS_WIN + || (m_filePath.length() >= 2 && (m_filePath.at(0) == QLatin1Char('/') && m_filePath.at(1) == QLatin1Char('/'))) +#endif + )); +} +#else +bool QFileSystemEntry::isRelative() const +{ + return !isAbsolute(); +} + +bool QFileSystemEntry::isAbsolute() const +{ + resolveFilePath(); + return (!m_filePath.isEmpty() && (m_filePath[0].unicode() == '/')); +} +#endif + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +bool QFileSystemEntry::isDriveRoot() const +{ + resolveFilePath(); + return (m_filePath.length() == 3 + && m_filePath.at(0).isLetter() && m_filePath.at(1) == QLatin1Char(':') + && m_filePath.at(2) == QLatin1Char('/')); +} +#endif + +bool QFileSystemEntry::isRoot() const +{ + resolveFilePath(); + if (m_filePath == QLatin1String("/") +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + || isDriveRoot() +#if defined(Q_OS_WIN) + || isUncRoot(m_filePath) +#endif +#endif + ) + return true; + + return false; +} + +bool QFileSystemEntry::isEmpty() const +{ + resolveNativeFilePath(); + return m_nativeFilePath.isEmpty(); +} + +// private methods + +void QFileSystemEntry::findLastSeparator() const +{ + if (m_lastSeparator == -2) { + resolveFilePath(); + m_lastSeparator = -1; + for (int i = m_filePath.size() - 1; i >= 0; --i) { + if (m_filePath[i].unicode() == '/') { + m_lastSeparator = i; + break; + } + } + } +} + +void QFileSystemEntry::findFileNameSeparators() const +{ + if (m_firstDotInFileName == -2) { + resolveFilePath(); + int firstDotInFileName = -1; + int lastDotInFileName = -1; + int lastSeparator = m_lastSeparator; + + int stop; + if (lastSeparator < 0) { + lastSeparator = -1; + stop = 0; + } else { + stop = lastSeparator; + } + + int i = m_filePath.size() - 1; + for (; i >= stop; --i) { + if (m_filePath[i].unicode() == '.') { + firstDotInFileName = lastDotInFileName = i; + break; + } else if (m_filePath[i].unicode() == '/') { + lastSeparator = i; + break; + } + } + + if (lastSeparator != i) { + for (--i; i >= stop; --i) { + if (m_filePath[i].unicode() == '.') + firstDotInFileName = i; + else if (m_filePath[i].unicode() == '/') { + lastSeparator = i; + break; + } + } + } + m_lastSeparator = lastSeparator; + m_firstDotInFileName = firstDotInFileName == -1 ? -1 : firstDotInFileName - qMax(0, lastSeparator); + if (lastDotInFileName == -1) + m_lastDotInFileName = -1; + else if (firstDotInFileName == lastDotInFileName) + m_lastDotInFileName = 0; + else + m_lastDotInFileName = lastDotInFileName - firstDotInFileName; + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystementry_p.h b/src/corelib/io/qfilesystementry_p.h new file mode 100644 index 0000000..2ce0a83 --- /dev/null +++ b/src/corelib/io/qfilesystementry_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILESYSTEMENTRY_P_H_INCLUDED +#define QFILESYSTEMENTRY_P_H_INCLUDED + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qstring.h> +#include <QtCore/qbytearray.h> + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +#define QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16 +#endif + +QT_BEGIN_NAMESPACE + +class QFileSystemEntry +{ +public: + +#ifndef QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16 + typedef QByteArray NativePath; +#else + typedef QString NativePath; +#endif + struct FromNativePath{}; + struct FromInternalPath{}; + + QFileSystemEntry(); + explicit QFileSystemEntry(const QString &filePath); + + QFileSystemEntry(const QString &filePath, FromInternalPath dummy); + QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath dummy); + QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath); + + QString filePath() const; + QString fileName() const; + QString path() const; + NativePath nativeFilePath() const; + QString baseName() const; + QString completeBaseName() const; + QString suffix() const; + QString completeSuffix() const; + bool isAbsolute() const; + bool isRelative() const; + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + bool isDriveRoot() const; +#endif + bool isRoot() const; + + bool isEmpty() const; + void clear() + { + *this = QFileSystemEntry(); + } + +private: + // creates the QString version out of the bytearray version + void resolveFilePath() const; + // creates the bytearray version out of the QString version + void resolveNativeFilePath() const; + // resolves the separator + void findLastSeparator() const; + // resolves the dots and the separator + void findFileNameSeparators() const; + + mutable QString m_filePath; // always has slashes as separator + mutable NativePath m_nativeFilePath; // native encoding and separators + + mutable qint16 m_lastSeparator; // index in m_filePath of last separator + mutable qint16 m_firstDotInFileName; // index after m_filePath for first dot (.) + mutable qint16 m_lastDotInFileName; // index after m_firstDotInFileName for last dot (.) +}; + +QT_END_NAMESPACE + +#endif // include guard diff --git a/src/corelib/io/qfilesystemiterator_p.h b/src/corelib/io/qfilesystemiterator_p.h new file mode 100644 index 0000000..66f4b1e --- /dev/null +++ b/src/corelib/io/qfilesystemiterator_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILESYSTEMITERATOR_P_H_INCLUDED +#define QFILESYSTEMITERATOR_P_H_INCLUDED + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qdir.h> +#include <QtCore/qdiriterator.h> +#include <QtCore/qstringlist.h> + +#include <QtCore/private/qfilesystementry_p.h> +#include <QtCore/private/qfilesystemmetadata_p.h> + +// Platform-specific headers +#if defined(Q_OS_WIN) +#elif defined (Q_OS_SYMBIAN) +#include <f32file.h> +#else +#include <QtCore/qscopedpointer.h> +#endif + +QT_BEGIN_NAMESPACE + +class QFileSystemIterator +{ +public: + QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters, + const QStringList &nameFilters, QDirIterator::IteratorFlags flags + = QDirIterator::FollowSymlinks | QDirIterator::Subdirectories); + ~QFileSystemIterator(); + + bool advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData); + +private: + QFileSystemEntry::NativePath nativePath; + + // Platform-specific data +#if defined(Q_OS_WIN) + QFileSystemEntry::NativePath dirPath; + HANDLE findFileHandle; + QStringList uncShares; + bool uncFallback; + int uncShareIndex; + bool onlyDirs; +#elif defined (Q_OS_SYMBIAN) + RDir dirHandle; + TEntryArray entries; + TInt lastError; + TInt entryIndex; +#else + QT_DIR *dir; + QT_DIRENT *dirEntry; +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) + // for readdir_r + QScopedPointer<QT_DIRENT, QScopedPointerPodDeleter> mt_file; +#endif + int lastError; +#endif + + Q_DISABLE_COPY(QFileSystemIterator) +}; + +QT_END_NAMESPACE + +#endif // include guard diff --git a/src/corelib/io/qfilesystemiterator_symbian.cpp b/src/corelib/io/qfilesystemiterator_symbian.cpp new file mode 100644 index 0000000..e316526 --- /dev/null +++ b/src/corelib/io/qfilesystemiterator_symbian.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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; + else if ((filters & QDir::PermissionMask) == QDir::Readable) + symbianMask = KEntryAttMatchExclusive | 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 new file mode 100644 index 0000000..00ccd41 --- /dev/null +++ b/src/corelib/io/qfilesystemiterator_unix.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qfilesystemiterator_p.h" + +#include <stdlib.h> +#include <errno.h> + +QT_BEGIN_NAMESPACE + +QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters, + const QStringList &nameFilters, QDirIterator::IteratorFlags flags) + : nativePath(entry.nativeFilePath()) + , dir(0) + , dirEntry(0) + , lastError(0) +{ + Q_UNUSED(filters) + Q_UNUSED(nameFilters) + Q_UNUSED(flags) + + if ((dir = QT_OPENDIR(nativePath.constData())) == 0) { + lastError = errno; + } else { + + if (!nativePath.endsWith('/')) + nativePath.append('/'); + +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) + // ### Race condition; we should use fpathconf and dirfd(). + size_t maxPathName = ::pathconf(nativePath.constData(), _PC_NAME_MAX); + if (maxPathName == size_t(-1)) + maxPathName = FILENAME_MAX; + maxPathName += sizeof(QT_DIRENT) + 1; + + QT_DIRENT *p = reinterpret_cast<QT_DIRENT*>(::malloc(maxPathName)); + Q_CHECK_PTR(p); + + mt_file.reset(p); +#endif + } +} + +QFileSystemIterator::~QFileSystemIterator() +{ + if (dir) + QT_CLOSEDIR(dir); +} + +bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData) +{ + if (!dir) + return false; + +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) + lastError = QT_READDIR_R(dir, mt_file.data(), &dirEntry); + if (lastError) + return false; +#else + // ### add local lock to prevent breaking reentrancy + dirEntry = QT_READDIR(dir); +#endif // _POSIX_THREAD_SAFE_FUNCTIONS + + if (dirEntry) { + fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name), QFileSystemEntry::FromNativePath()); + metaData.fillFromDirEnt(*dirEntry); + return true; + } + + lastError = errno; + return false; +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp new file mode 100644 index 0000000..b5fce12 --- /dev/null +++ b/src/corelib/io/qfilesystemiterator_win.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#if _WIN32_WINNT < 0x0500 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif + +#include "qfilesystemiterator_p.h" +#include "qfilesystemengine_p.h" +#include "qplatformdefs.h" + +#include <QtCore/qt_windows.h> + +QT_BEGIN_NAMESPACE + +bool done = true; + +QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters, + const QStringList &nameFilters, QDirIterator::IteratorFlags flags) + : nativePath(entry.nativeFilePath()) + , dirPath(entry.filePath()) + , findFileHandle(INVALID_HANDLE_VALUE) + , uncFallback(false) + , uncShareIndex(0) + , onlyDirs(false) +{ + Q_UNUSED(nameFilters) + Q_UNUSED(flags) + if (nativePath.endsWith(QLatin1String(".lnk"))) { + QFileSystemMetaData metaData; + QFileSystemEntry link = QFileSystemEngine::getLinkTarget(entry, metaData); + nativePath = link.nativeFilePath(); + } + if (!nativePath.endsWith(QLatin1Char('\\'))) + nativePath.append(QLatin1Char('\\')); + nativePath.append(QLatin1Char('*')); + if (!dirPath.endsWith(QLatin1Char('/'))) + dirPath.append(QLatin1Char('/')); + if ((filters & (QDir::Dirs|QDir::Drives)) && (!(filters & (QDir::Files)))) + onlyDirs = true; +} + +QFileSystemIterator::~QFileSystemIterator() +{ + if (findFileHandle != INVALID_HANDLE_VALUE) + FindClose(findFileHandle); +} + +bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData) +{ + bool haveData = false; + WIN32_FIND_DATA findData; + + if (findFileHandle == INVALID_HANDLE_VALUE && !uncFallback) { + haveData = true; + int infoLevel = 0 ; // FindExInfoStandard; + DWORD dwAdditionalFlags = 0; + if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) { + dwAdditionalFlags = 2; // FIND_FIRST_EX_LARGE_FETCH + infoLevel = 1 ; // FindExInfoBasic; + } + int searchOps = 0; // FindExSearchNameMatch + if (onlyDirs) + searchOps = 1 ; // FindExSearchLimitToDirectories + findFileHandle = FindFirstFileEx((const wchar_t *)nativePath.utf16(), FINDEX_INFO_LEVELS(infoLevel), &findData, + FINDEX_SEARCH_OPS(searchOps), 0, dwAdditionalFlags); + if (findFileHandle == INVALID_HANDLE_VALUE) { + if (nativePath.startsWith(QLatin1String("\\\\?\\UNC\\"))) { + QStringList parts = nativePath.split(QLatin1Char('\\'), QString::SkipEmptyParts); + if (parts.count() == 4 && QFileSystemEngine::uncListSharesOnServer( + QLatin1String("\\\\") + parts.at(2), &uncShares)) { + if (uncShares.isEmpty()) + return false; // No shares found in the server + else + uncFallback = true; + } + } + } + } + if (findFileHandle == INVALID_HANDLE_VALUE && !uncFallback) + return false; + // Retrieve the new file information. + if (!haveData) { + if (uncFallback) { + if (++uncShareIndex >= uncShares.count()) + return false; + } else { + if (!FindNextFile(findFileHandle, &findData)) + return false; + } + } + // Create the new file system entry & meta data. + if (uncFallback) { + fileEntry = QFileSystemEntry(dirPath + uncShares.at(uncShareIndex)); + metaData.fillFromFileAttribute(FILE_ATTRIBUTE_DIRECTORY); + return true; + } else { + QString fileName = QString::fromWCharArray(findData.cFileName); + fileEntry = QFileSystemEntry(dirPath + fileName); + metaData = QFileSystemMetaData(); + if (!fileName.endsWith(QLatin1String(".lnk"))) { + metaData.fillFromFindData(findData, true); + } + return true; + } + return false; +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h new file mode 100644 index 0000000..c4e11d9 --- /dev/null +++ b/src/corelib/io/qfilesystemmetadata_p.h @@ -0,0 +1,400 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILESYSTEMMETADATA_P_H_INCLUDED +#define QFILESYSTEMMETADATA_P_H_INCLUDED + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qplatformdefs.h" +#include <QtCore/qglobal.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qabstractfileengine.h> + +// Platform-specific includes +#if defined(Q_OS_WIN) +#ifndef IO_REPARSE_TAG_SYMLINK +#define IO_REPARSE_TAG_SYMLINK (0xA000000CL) +#endif +#elif defined(Q_OS_SYMBIAN) +#include <f32file.h> +#include <QtCore/private/qdatetime_p.h> +#endif + +QT_BEGIN_NAMESPACE + +class QFileSystemEngine; + +class QFileSystemMetaData +{ +public: + QFileSystemMetaData() + : knownFlagsMask(0) + { + } + + enum MetaDataFlag { + // Permissions, overlaps with QFile::Permissions + OtherReadPermission = 0x00000004, OtherWritePermission = 0x00000002, OtherExecutePermission = 0x00000001, + GroupReadPermission = 0x00000040, GroupWritePermission = 0x00000020, GroupExecutePermission = 0x00000010, + UserReadPermission = 0x00000400, UserWritePermission = 0x00000200, UserExecutePermission = 0x00000100, + OwnerReadPermission = 0x00004000, OwnerWritePermission = 0x00002000, OwnerExecutePermission = 0x00001000, + + OtherPermissions = OtherReadPermission | OtherWritePermission | OtherExecutePermission, + GroupPermissions = GroupReadPermission | GroupWritePermission | GroupExecutePermission, + UserPermissions = UserReadPermission | UserWritePermission | UserExecutePermission, + OwnerPermissions = OwnerReadPermission | OwnerWritePermission | OwnerExecutePermission, + + ReadPermissions = OtherReadPermission | GroupReadPermission | UserReadPermission | OwnerReadPermission, + WritePermissions = OtherWritePermission | GroupWritePermission | UserWritePermission | OwnerWritePermission, + ExecutePermissions = OtherExecutePermission | GroupExecutePermission | UserExecutePermission | OwnerExecutePermission, + + Permissions = OtherPermissions | GroupPermissions | UserPermissions | OwnerPermissions, + + // Type +#ifdef Q_OS_SYMBIAN + LinkType = 0, +#else + LinkType = 0x00010000, +#endif + FileType = 0x00020000, + DirectoryType = 0x00040000, +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) + BundleType = 0x00080000, + AliasType = 0x08000000, +#else + BundleType = 0x0, + AliasType = 0x0, +#endif +#if defined(Q_OS_WIN) + WinLnkType = 0x08000000, // Note: Uses the same position for AliasType on Mac +#else + WinLnkType = 0x0, +#endif + SequentialType = 0x00800000, // Note: overlaps with QAbstractFileEngine::RootFlag + + LegacyLinkType = LinkType | AliasType | WinLnkType, + + Type = LinkType | FileType | DirectoryType | BundleType | SequentialType | AliasType, + + // Attributes + HiddenAttribute = 0x00100000, + SizeAttribute = 0x00200000, // Note: overlaps with QAbstractFileEngine::LocalDiskFlag + ExistsAttribute = 0x00400000, + + Attributes = HiddenAttribute | SizeAttribute | ExistsAttribute, + + // Times + CreationTime = 0x01000000, // Note: overlaps with QAbstractFileEngine::Refresh + ModificationTime = 0x02000000, + AccessTime = 0x04000000, + + Times = CreationTime | ModificationTime | AccessTime, + + // Owner IDs + UserId = 0x10000000, + GroupId = 0x20000000, + + OwnerIds = UserId | GroupId, + + PosixStatFlags = QFileSystemMetaData::OtherPermissions + | QFileSystemMetaData::GroupPermissions + | QFileSystemMetaData::OwnerPermissions + | QFileSystemMetaData::FileType + | QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::SequentialType + | QFileSystemMetaData::SizeAttribute + | QFileSystemMetaData::Times + | QFileSystemMetaData::OwnerIds, + + SymbianTEntryFlags = QFileSystemMetaData::Permissions + | QFileSystemMetaData::FileType + | QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::SequentialType + | QFileSystemMetaData::Attributes + | QFileSystemMetaData::Times, +#if defined(Q_OS_WIN) + WinStatFlags = QFileSystemMetaData::FileType + | QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::HiddenAttribute + | QFileSystemMetaData::ExistsAttribute + | QFileSystemMetaData::SizeAttribute + | QFileSystemMetaData::Times, +#endif + + AllMetaDataFlags = 0xFFFFFFFF + + }; + Q_DECLARE_FLAGS(MetaDataFlags, MetaDataFlag) + + bool hasFlags(MetaDataFlags flags) const + { + return ((knownFlagsMask & flags) == flags); + } + + MetaDataFlags missingFlags(MetaDataFlags flags) + { + return flags & ~knownFlagsMask; + } + + void clear() + { + knownFlagsMask = 0; + } + + void clearFlags(MetaDataFlags flags = AllMetaDataFlags) + { + knownFlagsMask &= ~flags; + } + + bool exists() const { return (entryFlags & ExistsAttribute); } + + bool isLink() const { return (entryFlags & LinkType); } + bool isFile() const { return (entryFlags & FileType); } + bool isDirectory() const { return (entryFlags & DirectoryType); } + bool isBundle() const; + bool isAlias() const; + bool isLegacyLink() const { return (entryFlags & LegacyLinkType); } + bool isSequential() const { return (entryFlags & SequentialType); } + bool isHidden() const { return (entryFlags & HiddenAttribute); } +#if defined(Q_OS_WIN) + bool isLnkFile() const { return (entryFlags & WinLnkType); } +#else + bool isLnkFile() const { return false; } +#endif + + qint64 size() const { return size_; } + + QFile::Permissions permissions() const { return QFile::Permissions(Permissions & entryFlags); } + + QDateTime creationTime() const; + QDateTime modificationTime() const; + QDateTime accessTime() const; + + QDateTime fileTime(QAbstractFileEngine::FileTime time) const; + uint userId() const; + uint groupId() const; + uint ownerId(QAbstractFileEngine::FileOwner owner) const; + +#ifdef Q_OS_UNIX + void fillFromStatBuf(const QT_STATBUF &statBuffer); + void fillFromDirEnt(const QT_DIRENT &statBuffer); +#endif +#ifdef Q_OS_SYMBIAN + void fillFromTEntry(const TEntry& entry); + void fillFromVolumeInfo(const TVolumeInfo& info); +#endif + +#if defined(Q_OS_WIN) + inline void fillFromFileAttribute(DWORD fileAttribute, bool isDriveRoot = false); + inline void fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType = false, bool isDriveRoot = false); + inline void fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo); +#endif +private: + friend class QFileSystemEngine; + + MetaDataFlags knownFlagsMask; + MetaDataFlags entryFlags; + + qint64 size_; + + // Platform-specific data goes here: +#if defined(Q_OS_WIN) + DWORD fileAttribute_; + FILETIME creationTime_; + FILETIME lastAccessTime_; + FILETIME lastWriteTime_; +#elif defined(Q_OS_SYMBIAN) + TTime modificationTime_; +#else + time_t creationTime_; + time_t modificationTime_; + time_t accessTime_; + + uint userId_; + uint groupId_; +#endif + +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags) + +#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) +inline bool QFileSystemMetaData::isBundle() const { return (entryFlags & BundleType); } +inline bool QFileSystemMetaData::isAlias() const { return (entryFlags & AliasType); } +#else +inline bool QFileSystemMetaData::isBundle() const { return false; } +inline bool QFileSystemMetaData::isAlias() const { return false; } +#endif + +#if (defined(Q_OS_UNIX) && !defined (Q_OS_SYMBIAN)) || defined (Q_OS_WIN) +inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime time) const +{ + switch (time) { + case QAbstractFileEngine::ModificationTime: + return modificationTime(); + + case QAbstractFileEngine::AccessTime: + return accessTime(); + + case QAbstractFileEngine::CreationTime: + return creationTime(); + } + + return QDateTime(); +} +#endif + +#if defined(Q_OS_UNIX) && !defined (Q_OS_SYMBIAN) +inline QDateTime QFileSystemMetaData::creationTime() const { return QDateTime::fromTime_t(creationTime_); } +inline QDateTime QFileSystemMetaData::modificationTime() const { return QDateTime::fromTime_t(modificationTime_); } +inline QDateTime QFileSystemMetaData::accessTime() const { return QDateTime::fromTime_t(accessTime_); } + +inline uint QFileSystemMetaData::userId() const { return userId_; } +inline uint QFileSystemMetaData::groupId() const { return groupId_; } + +inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const +{ + if (owner == QAbstractFileEngine::OwnerUser) + return userId(); + else + return groupId(); +} +#endif + +#ifdef Q_OS_SYMBIAN +inline QDateTime QFileSystemMetaData::creationTime() const { return modificationTime(); } +inline QDateTime QFileSystemMetaData::modificationTime() const { return qt_symbian_TTime_To_QDateTime(modificationTime_); } +inline QDateTime QFileSystemMetaData::accessTime() const { return modificationTime(); } + +inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime time) const +{ + Q_UNUSED(time); + return modificationTime(); +} +inline uint QFileSystemMetaData::userId() const { return (uint) -2; } +inline uint QFileSystemMetaData::groupId() const { return (uint) -2; } +inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const +{ + Q_UNUSED(owner); + return (uint) -2; +} +#endif + +#if defined(Q_OS_WIN) +inline uint QFileSystemMetaData::userId() const { return (uint) -2; } +inline uint QFileSystemMetaData::groupId() const { return (uint) -2; } +inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const +{ + if (owner == QAbstractFileEngine::OwnerUser) + return userId(); + else + return groupId(); +} + +inline void QFileSystemMetaData::fillFromFileAttribute(DWORD fileAttribute,bool isDriveRoot) +{ + fileAttribute_ = fileAttribute; + // Ignore the hidden attribute for drives. + if (!isDriveRoot && (fileAttribute_ & FILE_ATTRIBUTE_HIDDEN)) + entryFlags |= HiddenAttribute; + entryFlags |= ((fileAttribute & FILE_ATTRIBUTE_DIRECTORY) ? DirectoryType: FileType); + entryFlags |= ExistsAttribute; + knownFlagsMask |= FileType | DirectoryType | HiddenAttribute | ExistsAttribute; +} + +inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType, bool isDriveRoot) +{ + fillFromFileAttribute(findData.dwFileAttributes, isDriveRoot); + creationTime_ = findData.ftCreationTime; + lastAccessTime_ = findData.ftLastAccessTime; + lastWriteTime_ = findData.ftLastWriteTime; + if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) { + size_ = 0; + } else { + size_ = findData.nFileSizeHigh; + size_ <<= 32; + size_ += findData.nFileSizeLow; + } + knownFlagsMask |= Times | SizeAttribute; + if (setLinkType) { + knownFlagsMask |= LinkType; + entryFlags &= ~LinkType; +#if !defined(Q_OS_WINCE) + if ((fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) + && (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK + || findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) { + entryFlags |= LinkType; + } +#endif + + } +} + +inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo) +{ + fillFromFileAttribute(fileInfo.dwFileAttributes); + creationTime_ = fileInfo.ftCreationTime; + lastAccessTime_ = fileInfo.ftLastAccessTime; + lastWriteTime_ = fileInfo.ftLastWriteTime; + if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) { + size_ = 0; + } else { + size_ = fileInfo.nFileSizeHigh; + size_ <<= 32; + size_ += fileInfo.nFileSizeLow; + } + knownFlagsMask |= Times | SizeAttribute; +} +#endif + +QT_END_NAMESPACE + +#endif // include guard diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 62b9981..ae301f7 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -41,6 +41,7 @@ #include "qfsfileengine_p.h" #include "qfsfileengine_iterator_p.h" +#include "qfilesystemengine_p.h" #include "qdatetime.h" #include "qdiriterator.h" #include "qset.h" @@ -119,6 +120,9 @@ void QFSFileEnginePrivate::init() openMode = QIODevice::NotOpen; fd = -1; fh = 0; +#ifdef Q_OS_SYMBIAN + fileHandleForMaps = -1; +#endif lastIOCommand = IOFlushCommand; lastFlushFailed = false; closeFileHandle = false; @@ -133,117 +137,13 @@ void QFSFileEnginePrivate::init() } /*! - \internal - - Returns the canonicalized form of \a path (i.e., with all symlinks - resolved, and all redundant path elements removed. -*/ -QString QFSFileEnginePrivate::canonicalized(const QString &path) -{ - if (path.isEmpty()) - return path; - - // FIXME let's see if this stuff works, then we might be able to remove some of the other code. -#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) - if (path.size() == 1 && path.at(0) == QLatin1Char('/')) - return path; -#endif -#if defined(Q_OS_LINUX) || defined(Q_OS_SYMBIAN) || defined(Q_OS_MAC) - // ... but Linux with uClibc does not have it -#if !defined(__UCLIBC__) - char *ret = 0; -#if defined(Q_OS_MAC) && !defined(QT_NO_CORESERVICES) - // Mac OS X 10.5.x doesn't support the realpath(X,0) extension we use here. - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) { - ret = realpath(path.toLocal8Bit().constData(), (char*)0); - } else { - // on 10.5 we can use FSRef to resolve the file path. - FSRef fsref; - if (FSPathMakeRef((const UInt8 *)QDir::cleanPath(path).toUtf8().data(), &fsref, 0) == noErr) { - CFURLRef urlref = CFURLCreateFromFSRef(NULL, &fsref); - CFStringRef canonicalPath = CFURLCopyFileSystemPath(urlref, kCFURLPOSIXPathStyle); - QString ret = QCFString::toQString(canonicalPath); - CFRelease(canonicalPath); - CFRelease(urlref); - return ret; - } - } -#else - ret = realpath(path.toLocal8Bit().constData(), (char*)0); -#endif - if (ret) { - QString canonicalPath = QDir::cleanPath(QString::fromLocal8Bit(ret)); - free(ret); - return canonicalPath; - } -#endif -#endif - - QFileInfo fi; - const QChar slash(QLatin1Char('/')); - QString tmpPath = path; - int separatorPos = 0; - QSet<QString> nonSymlinks; - QSet<QString> known; - - known.insert(path); - do { -#ifdef Q_OS_WIN - if (separatorPos == 0) { - if (tmpPath.size() >= 2 && tmpPath.at(0) == slash && tmpPath.at(1) == slash) { - // UNC, skip past the first two elements - separatorPos = tmpPath.indexOf(slash, 2); - } else if (tmpPath.size() >= 3 && tmpPath.at(1) == QLatin1Char(':') && tmpPath.at(2) == slash) { - // volume root, skip since it can not be a symlink - separatorPos = 2; - } - } - if (separatorPos != -1) -#endif - separatorPos = tmpPath.indexOf(slash, separatorPos + 1); - QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos); - if ( -#ifdef Q_OS_SYMBIAN - // Symbian doesn't support directory symlinks, so do not check for link unless we - // are handling the last path element. This not only slightly improves performance, - // but also saves us from lot of unnecessary platform security check failures - // when dealing with files under *:/private directories. - separatorPos == -1 && -#endif - !nonSymlinks.contains(prefix)) { - fi.setFile(prefix); - if (fi.isSymLink()) { - QString target = fi.symLinkTarget(); - if(QFileInfo(target).isRelative()) - target = fi.absolutePath() + slash + target; - if (separatorPos != -1) { - if (fi.isDir() && !target.endsWith(slash)) - target.append(slash); - target.append(tmpPath.mid(separatorPos)); - } - tmpPath = QDir::cleanPath(target); - separatorPos = 0; - - if (known.contains(tmpPath)) - return QString(); - known.insert(tmpPath); - } else { - nonSymlinks.insert(prefix); - } - } - } while (separatorPos != -1); - - return QDir::cleanPath(tmpPath); -} - -/*! Constructs a QFSFileEngine for the file name \a file. */ -QFSFileEngine::QFSFileEngine(const QString &file) : QAbstractFileEngine(*new QFSFileEnginePrivate) +QFSFileEngine::QFSFileEngine(const QString &file) + : QAbstractFileEngine(*new QFSFileEnginePrivate) { Q_D(QFSFileEngine); - d->filePath = QDir::fromNativeSeparators(file); - d->nativeInitFileName(); + d->fileEntry = QFileSystemEntry(file); } /*! @@ -292,8 +192,7 @@ void QFSFileEngine::setFileName(const QString &file) { Q_D(QFSFileEngine); d->init(); - d->filePath = QDir::fromNativeSeparators(file); - d->nativeInitFileName(); + d->fileEntry = QFileSystemEntry(file); } /*! @@ -302,7 +201,7 @@ void QFSFileEngine::setFileName(const QString &file) bool QFSFileEngine::open(QIODevice::OpenMode openMode) { Q_D(QFSFileEngine); - if (d->filePath.isEmpty()) { + if (d->fileEntry.isEmpty()) { qWarning("QFSFileEngine::open: No file name specified"); setError(QFile::OpenError, QLatin1String("No file name specified")); return false; @@ -344,8 +243,7 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh) d->openMode = openMode; d->lastFlushFailed = false; d->closeFileHandle = false; - d->nativeFilePath.clear(); - d->filePath.clear(); + d->fileEntry.clear(); d->tried_stat = 0; d->fd = -1; @@ -401,8 +299,7 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, int fd) d->openMode = openMode; d->lastFlushFailed = false; d->closeFileHandle = false; - d->nativeFilePath.clear(); - d->filePath.clear(); + d->fileEntry.clear(); d->fh = 0; d->fd = -1; d->tried_stat = 0; @@ -458,7 +355,12 @@ bool QFSFileEngine::close() bool QFSFileEnginePrivate::closeFdFh() { Q_Q(QFSFileEngine); - if (fd == -1 && !fh) + if (fd == -1 && !fh +#ifdef Q_OS_SYMBIAN + && !symbianFile.SubSessionHandle() + && fileHandleForMaps == -1 +#endif + ) return false; // Flush the file if it's buffered, and if the last flush didn't fail. @@ -466,10 +368,24 @@ bool QFSFileEnginePrivate::closeFdFh() bool closed = true; tried_stat = 0; +#ifdef Q_OS_SYMBIAN + // Map handle is always owned by us so always close it + if (fileHandleForMaps >= 0) { + QT_CLOSE(fileHandleForMaps); + fileHandleForMaps = -1; + } +#endif + // Close the file if we created the handle. if (closeFileHandle) { int ret; do { +#ifdef Q_OS_SYMBIAN + if (symbianFile.SubSessionHandle()) { + symbianFile.Close(); + ret = 0; + } else +#endif if (fh) { // Close buffered file. ret = fclose(fh) != 0 ? -1 : 0; @@ -549,28 +465,19 @@ qint64 QFSFileEngine::size() const /*! \internal */ +#ifndef Q_OS_WIN qint64 QFSFileEnginePrivate::sizeFdFh() const { Q_Q(const QFSFileEngine); - // ### Fix this function, it should not stat unless the file is closed. - QT_STATBUF st; - int ret = 0; const_cast<QFSFileEngine *>(q)->flush(); - if (fh && nativeFilePath.isEmpty()) { - // Buffered stdlib mode. - // ### This should really be an ftell - ret = QT_FSTAT(QT_FILENO(fh), &st); - } else if (fd == -1) { - // Stateless stat. - ret = QT_STAT(nativeFilePath.constData(), &st); - } else { - // Unbuffered stdio mode. - ret = QT_FSTAT(fd, &st); - } - if (ret == -1) + + tried_stat = 0; + metaData.clearFlags(QFileSystemMetaData::SizeAttribute); + if (!doStat(QFileSystemMetaData::SizeAttribute)) return 0; - return st.st_size; + return metaData.size(); } +#endif /*! \reimp @@ -877,18 +784,14 @@ bool QFSFileEngine::isSequential() const /*! \internal */ +#ifdef Q_OS_UNIX bool QFSFileEnginePrivate::isSequentialFdFh() const { - if (!tried_stat) - doStat(); - if (could_stat) { -#ifdef Q_OS_UNIX - return (st.st_mode & S_IFMT) != S_IFREG; - // ### WINDOWS! -#endif - } + if (doStat(QFileSystemMetaData::SequentialType)) + return metaData.isSequential(); return true; } +#endif /*! \reimp diff --git a/src/corelib/io/qfsfileengine_iterator.cpp b/src/corelib/io/qfsfileengine_iterator.cpp index 7e7d70a..f6f08c7 100644 --- a/src/corelib/io/qfsfileengine_iterator.cpp +++ b/src/corelib/io/qfsfileengine_iterator.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qfsfileengine_iterator_p.h" +#include "qfileinfo_p.h" #include "qvariant.h" #ifndef QT_NO_FSFILEENGINE @@ -48,13 +49,23 @@ QT_BEGIN_NAMESPACE QFSFileEngineIterator::QFSFileEngineIterator(QDir::Filters filters, const QStringList &filterNames) : QAbstractFileEngineIterator(filters, filterNames) + , done(false) { - newPlatformSpecifics(); } QFSFileEngineIterator::~QFSFileEngineIterator() { - deletePlatformSpecifics(); +} + +bool QFSFileEngineIterator::hasNext() const +{ + if (!done && !nativeIterator) { + nativeIterator.reset(new QFileSystemIterator(QFileSystemEntry(path()), + filters(), nameFilters())); + advance(); + } + + return !done; } QString QFSFileEngineIterator::next() @@ -66,14 +77,28 @@ QString QFSFileEngineIterator::next() return currentFilePath(); } +void QFSFileEngineIterator::advance() const +{ + currentInfo = nextInfo; + + QFileSystemEntry entry; + QFileSystemMetaData data; + if (nativeIterator->advance(entry, data)) { + nextInfo = QFileInfo(new QFileInfoPrivate(entry, data)); + } else { + done = true; + nativeIterator.reset(); + } +} + QString QFSFileEngineIterator::currentFileName() const { - return currentEntry; + return currentInfo.fileName(); } QFileInfo QFSFileEngineIterator::currentFileInfo() const { - return QAbstractFileEngineIterator::currentFileInfo(); + return currentInfo; } QT_END_NAMESPACE diff --git a/src/corelib/io/qfsfileengine_iterator_p.h b/src/corelib/io/qfsfileengine_iterator_p.h index be670e0..ac9598d 100644 --- a/src/corelib/io/qfsfileengine_iterator_p.h +++ b/src/corelib/io/qfsfileengine_iterator_p.h @@ -54,6 +54,7 @@ // #include "qabstractfileengine.h" +#include "qfilesystemiterator_p.h" #include "qdir.h" #ifndef QT_NO_FSFILEENGINE @@ -76,13 +77,11 @@ public: QFileInfo currentFileInfo() const; private: - QFSFileEngineIteratorPlatformSpecificData *platform; - friend class QFSFileEngineIteratorPlatformSpecificData; - void newPlatformSpecifics(); - void deletePlatformSpecifics(); - void advance(); - - QString currentEntry; + void advance() const; + mutable QScopedPointer<QFileSystemIterator> nativeIterator; + mutable QFileInfo currentInfo; + mutable QFileInfo nextInfo; + mutable bool done; }; QT_END_NAMESPACE diff --git a/src/corelib/io/qfsfileengine_iterator_unix.cpp b/src/corelib/io/qfsfileengine_iterator_unix.cpp deleted file mode 100644 index bfdb03e..0000000 --- a/src/corelib/io/qfsfileengine_iterator_unix.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, 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. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qplatformdefs.h" -#include "qfsfileengine_iterator_p.h" - -#include <QtCore/qvariant.h> - -#ifndef QT_NO_FSFILEENGINE - -QT_BEGIN_NAMESPACE - -class QFSFileEngineIteratorPlatformSpecificData -{ -public: - inline QFSFileEngineIteratorPlatformSpecificData() - : dir(0), dirEntry(0), done(false) -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) - , mt_file(0) -#endif - {} - - QT_DIR *dir; - QT_DIRENT *dirEntry; - bool done; - -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) - // for readdir_r - QT_DIRENT *mt_file; -#endif -}; - -void QFSFileEngineIterator::advance() -{ - currentEntry = platform->dirEntry ? QFile::decodeName(QByteArray(platform->dirEntry->d_name)) : QString(); - - if (!platform->dir) - return; - -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) - if (QT_READDIR_R(platform->dir, platform->mt_file, &platform->dirEntry) != 0) - platform->done = true; -#else - // ### add local lock to prevent breaking reentrancy - platform->dirEntry = QT_READDIR(platform->dir); -#endif // _POSIX_THREAD_SAFE_FUNCTIONS - if (!platform->dirEntry) { - QT_CLOSEDIR(platform->dir); - platform->dir = 0; - platform->done = true; -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) - delete [] platform->mt_file; - platform->mt_file = 0; -#endif - } -} - -void QFSFileEngineIterator::newPlatformSpecifics() -{ - platform = new QFSFileEngineIteratorPlatformSpecificData; -} - -void QFSFileEngineIterator::deletePlatformSpecifics() -{ - if (platform->dir) { - QT_CLOSEDIR(platform->dir); -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) - delete [] platform->mt_file; - platform->mt_file = 0; -#endif - } - delete platform; - platform = 0; -} - -bool QFSFileEngineIterator::hasNext() const -{ - if (!platform->done && !platform->dir) { - QFSFileEngineIterator *that = const_cast<QFSFileEngineIterator *>(this); - if ((that->platform->dir = QT_OPENDIR(QFile::encodeName(path()).data())) == 0) { - that->platform->done = true; - } else { - // ### Race condition; we should use fpathconf and dirfd(). - long maxPathName = ::pathconf(QFile::encodeName(path()).data(), _PC_NAME_MAX); - if ((int) maxPathName == -1) - maxPathName = FILENAME_MAX; - maxPathName += sizeof(QT_DIRENT) + 1; -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) - if (that->platform->mt_file) - delete [] that->platform->mt_file; - that->platform->mt_file = (QT_DIRENT *)new char[maxPathName]; -#endif - - that->advance(); - } - } - return !platform->done; -} - -QT_END_NAMESPACE - -#endif // QT_NO_FSFILEENGINE diff --git a/src/corelib/io/qfsfileengine_iterator_win.cpp b/src/corelib/io/qfsfileengine_iterator_win.cpp deleted file mode 100644 index 7181025..0000000 --- a/src/corelib/io/qfsfileengine_iterator_win.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, 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. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qfsfileengine_iterator_p.h" -#include "qfsfileengine_p.h" -#include "qplatformdefs.h" - -#include <QtCore/qvariant.h> - -QT_BEGIN_NAMESPACE - -class QFSFileEngineIteratorPlatformSpecificData -{ -public: - inline QFSFileEngineIteratorPlatformSpecificData() - : uncShareIndex(-1), findFileHandle(INVALID_HANDLE_VALUE), - done(false), uncFallback(false) - {} - - QFSFileEngineIterator *it; - - QStringList uncShares; - int uncShareIndex; - - HANDLE findFileHandle; - WIN32_FIND_DATA findData; - bool done; - bool uncFallback; - - void saveCurrentFileName(); -}; - -void QFSFileEngineIteratorPlatformSpecificData::saveCurrentFileName() -{ - if (uncFallback) { - // Windows share / UNC path - it->currentEntry = uncShares.at(uncShareIndex - 1); - } else { - // Local directory - it->currentEntry = QString::fromWCharArray(findData.cFileName); - } -} - -void QFSFileEngineIterator::advance() -{ - platform->saveCurrentFileName(); - - if (platform->done) - return; - - if (platform->uncFallback) { - ++platform->uncShareIndex; - } else if (platform->findFileHandle != INVALID_HANDLE_VALUE) { - if (!FindNextFile(platform->findFileHandle, &platform->findData)) { - platform->done = true; - FindClose(platform->findFileHandle); - } - } -} - -void QFSFileEngineIterator::newPlatformSpecifics() -{ - platform = new QFSFileEngineIteratorPlatformSpecificData; - platform->it = this; -} - -void QFSFileEngineIterator::deletePlatformSpecifics() -{ - delete platform; - platform = 0; -} - -bool QFSFileEngineIterator::hasNext() const -{ - if (platform->done) - return false; - - if (platform->uncFallback) - return platform->uncShareIndex > 0 && platform->uncShareIndex <= platform->uncShares.size(); - - if (platform->findFileHandle == INVALID_HANDLE_VALUE) { - QString path = this->path(); - // Local directory - if (path.endsWith(QLatin1String(".lnk"))) - path = QFileInfo(path).readLink(); - - if (!path.endsWith(QLatin1Char('/'))) - path.append(QLatin1Char('/')); - path.append(QLatin1String("*.*")); - - QString fileName = QFSFileEnginePrivate::longFileName(path); - platform->findFileHandle = FindFirstFile((const wchar_t *)fileName.utf16(), &platform->findData); - - if (platform->findFileHandle == INVALID_HANDLE_VALUE) { - if (path.startsWith(QLatin1String("//"))) { - path = this->path(); - // UNC - QStringList parts = QDir::toNativeSeparators(path).split(QLatin1Char('\\'), QString::SkipEmptyParts); - - if (parts.count() == 1 && QFSFileEnginePrivate::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(0), - &platform->uncShares)) { - if (platform->uncShares.isEmpty()) { - platform->done = true; - } else { - platform->uncShareIndex = 1; - } - platform->uncFallback = true; - } else { - platform->done = true; - } - } else { - platform->done = true; - } - } - - if (!platform->done && (!platform->uncFallback || !platform->uncShares.isEmpty())) - platform->saveCurrentFileName(); - } - - return !platform->done; -} - -QT_END_NAMESPACE diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index e9e55f3..7c088b8 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -56,8 +56,14 @@ #include "qplatformdefs.h" #include "QtCore/qfsfileengine.h" #include "private/qabstractfileengine_p.h" +#include <QtCore/private/qfilesystementry_p.h> +#include <QtCore/private/qfilesystemmetadata_p.h> #include <qhash.h> +#ifdef Q_OS_SYMBIAN +#include <f32file.h> +#endif + #ifndef QT_NO_FSFILEENGINE QT_BEGIN_NAMESPACE @@ -74,13 +80,10 @@ public: #ifdef Q_WS_WIN static QString longFileName(const QString &path); #endif - static QString canonicalized(const QString &path); - QString filePath; - QByteArray nativeFilePath; + QFileSystemEntry fileEntry; QIODevice::OpenMode openMode; - void nativeInitFileName(); bool nativeOpen(QIODevice::OpenMode openMode); bool openFh(QIODevice::OpenMode flags, FILE *fh); bool openFd(QIODevice::OpenMode flags, int fd); @@ -89,7 +92,9 @@ public: bool nativeFlush(); bool flushFh(); qint64 nativeSize() const; +#ifndef Q_OS_WIN qint64 sizeFdFh() const; +#endif qint64 nativePos() const; qint64 posFdFh() const; bool nativeSeek(qint64); @@ -102,12 +107,42 @@ public: qint64 writeFdFh(const char *data, qint64 len); int nativeHandle() const; bool nativeIsSequential() const; +#ifndef Q_OS_WIN bool isSequentialFdFh() const; +#endif uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags); bool unmap(uchar *ptr); + mutable QFileSystemMetaData metaData; + FILE *fh; +#ifdef Q_OS_SYMBIAN +#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API + RFile64 symbianFile; + TInt64 symbianFilePos; +#else + RFile symbianFile; + + /** + * The cursor position in the underlying file. This differs + * from devicePos because the latter is updated on calls to + * writeData, even if no data was physically transferred to + * the file, but instead stored in the write buffer. + * + * iFilePos is updated on calls to RFile::Read and + * RFile::Write. It is also updated on calls to seek() but + * RFile::Seek is not called when that happens because + * Symbian supports positioned reads and writes, saving a file + * server call, and because Symbian does not support seeking + * past the end of a file. + */ + TInt symbianFilePos; +#endif + mutable int fileHandleForMaps; + int getMapHandle(); +#endif + #ifdef Q_WS_WIN HANDLE fileHandle; HANDLE mapHandle; @@ -120,7 +155,6 @@ public: mutable DWORD fileAttrib; #else QHash<uchar *, QPair<int /*offset % PageSize*/, size_t /*length + offset % PageSize*/> > maps; - mutable QT_STATBUF st; #endif int fd; @@ -142,23 +176,17 @@ public: mutable uint is_link : 1; #endif - bool doStat() const; +#if defined(Q_OS_WIN) + bool doStat(QFileSystemMetaData::MetaDataFlags flags) const; +#else + bool doStat(QFileSystemMetaData::MetaDataFlags flags = QFileSystemMetaData::PosixStatFlags) const; +#endif bool isSymlink() const; #if defined(Q_OS_WIN32) int sysOpen(const QString &, int flags); #endif -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) - static void resolveLibs(); - static bool resolveUNCLibs(); - static bool uncListSharesOnServer(const QString &server, QStringList *list); -#endif - -#ifdef Q_OS_SYMBIAN - void setSymbianError(int symbianError, QFile::FileError defaultError, QString defaultString); -#endif - protected: QFSFileEnginePrivate(); diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 03e7283..1e1b35b 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -43,6 +43,8 @@ #include "qabstractfileengine.h" #include "private/qfsfileengine_p.h" #include "private/qcore_unix_p.h" +#include "qfilesystementry_p.h" +#include "qfilesystemengine_p.h" #ifndef QT_NO_FSFILEENGINE @@ -67,7 +69,6 @@ QT_BEGIN_NAMESPACE - #if defined(Q_OS_SYMBIAN) /*! \internal @@ -82,56 +83,25 @@ static bool isRelativePathSymbian(const QString& fileName) || (fileName.at(0) == QLatin1Char('/') && fileName.at(1) == QLatin1Char('/'))))); } -/*! - \internal - convert symbian error code to the one suitable for setError. - example usage: setSymbianError(err, QFile::CopyError, QLatin1String("copy error")) -*/ -void QFSFileEnginePrivate::setSymbianError(int symbianError, QFile::FileError defaultError, QString defaultString) -{ - Q_Q(QFSFileEngine); - switch (symbianError) { - case KErrNone: - q->setError(QFile::NoError, QLatin1String("")); - break; - case KErrAccessDenied: - q->setError(QFile::PermissionsError, QLatin1String("access denied")); - break; - case KErrPermissionDenied: - q->setError(QFile::PermissionsError, QLatin1String("permission denied")); - break; - case KErrAbort: - q->setError(QFile::AbortError, QLatin1String("aborted")); - break; - case KErrCancel: - q->setError(QFile::AbortError, QLatin1String("cancelled")); - break; - case KErrTimedOut: - q->setError(QFile::TimeOutError, QLatin1String("timed out")); - break; - default: - q->setError(defaultError, defaultString); - break; - } -} - #endif +#ifndef Q_OS_SYMBIAN /*! \internal Returns the stdlib open string corresponding to a QIODevice::OpenMode. */ -static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QByteArray &fileName) +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) { - QT_STATBUF statBuf; - if (!fileName.isEmpty() - && QT_STAT(fileName, &statBuf) == 0 - && (statBuf.st_mode & S_IFMT) == S_IFREG) { + metaData.clearFlags(QFileSystemMetaData::FileType); + if (!fileEntry.isEmpty() + && QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::FileType) + && metaData.isFile()) { mode += '+'; } else { mode = "wb+"; @@ -155,6 +125,7 @@ static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QB return mode; } +#endif /*! \internal @@ -184,6 +155,7 @@ static inline int openModeToOpenFlags(QIODevice::OpenMode mode) return oflags; } +#ifndef Q_OS_SYMBIAN /*! \internal @@ -194,15 +166,92 @@ static inline bool setCloseOnExec(int fd) { return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1; } +#endif +#ifdef Q_OS_SYMBIAN /*! \internal */ -void QFSFileEnginePrivate::nativeInitFileName() +bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) { - nativeFilePath = QFile::encodeName(filePath); -} + Q_Q(QFSFileEngine); + + fh = 0; + fd = -1; + + QString fn(QFileSystemEngine::absoluteName(fileEntry).nativeFilePath()); + RFs& fs = qt_s60GetRFs(); + + TUint symbianMode = 0; + + if(openMode & QIODevice::ReadOnly) + symbianMode |= EFileRead; + if(openMode & QIODevice::WriteOnly) + symbianMode |= EFileWrite; + if(openMode & QIODevice::Text) + symbianMode |= EFileStreamText; + + // pre Symbian 9.4, file I/O is always unbuffered, and the enum values don't exist + if(QSysInfo::symbianVersion() >= QSysInfo::SV_9_4) { + if (openMode & QFile::Unbuffered) { + if (openMode & QIODevice::WriteOnly) + symbianMode |= 0x00001000; //EFileWriteDirectIO; + // ### Unbuffered read is not used, because it prevents file open in /resource + // ### and has no obvious benefits + } else { + if (openMode & QIODevice::WriteOnly) + symbianMode |= 0x00000800; //EFileWriteBuffered; + // use implementation defaults for read buffering + } + } + + // Until Qt supports file sharing, we can't support EFileShareReadersOrWriters safely, + // but Qt does this on other platforms and autotests rely on it. + // The reason is that Unix locks are only advisory - the application needs to test the + // lock after opening the file. Symbian and Windows locks are mandatory - opening a + // locked file will fail. + symbianMode |= EFileShareReadersOrWriters; + + TInt r; + //note QIODevice::Truncate only has meaning for read/write access + //write-only files are always truncated unless append is specified + //reference openModeToOpenFlags in qfsfileengine_unix.cpp + if ((openMode & QIODevice::Truncate) || (!(openMode & QIODevice::ReadOnly) && !(openMode & QIODevice::Append))) { + r = symbianFile.Replace(fs, qt_QString2TPtrC(fn), symbianMode); + } else { + r = symbianFile.Open(fs, qt_QString2TPtrC(fn), symbianMode); + if (r == KErrNotFound && (openMode & QIODevice::WriteOnly)) { + r = symbianFile.Create(fs, qt_QString2TPtrC(fn), symbianMode); + } + } + + if (r == KErrNone) { +#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API + TInt64 size; +#else + TInt size; +#endif + r = symbianFile.Size(size); + if (r==KErrNone) { + if (openMode & QIODevice::Append) + symbianFilePos = size; + else + symbianFilePos = 0; + //TODO: port this (QFileSystemMetaData in open?) + //cachedSize = size; + } + } + if (r != KErrNone) { + q->setError(QFile::OpenError, QSystemError(r, QSystemError::NativeError).toString()); + symbianFile.Close(); + return false; + } + + closeFileHandle = true; + return true; +} +#else /*! \internal */ @@ -215,7 +264,7 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) // Try to open the file in unbuffered mode. do { - fd = QT_OPEN(nativeFilePath.constData(), flags, 0666); + fd = QT_OPEN(fileEntry.nativeFilePath().constData(), flags, 0666); } while (fd == -1 && errno == EINTR); // On failure, return and report the error. @@ -228,13 +277,11 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) if (!(openMode & QIODevice::WriteOnly)) { // we don't need this check if we tried to open for writing because then // we had received EISDIR anyway. - QT_STATBUF statBuf; - if (QT_FSTAT(fd, &statBuf) != -1) { - if ((statBuf.st_mode & S_IFMT) == S_IFDIR) { - q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); - QT_CLOSE(fd); - return false; - } + if (QFileSystemEngine::fillMetaData(fd, metaData) + && metaData.isDirectory()) { + q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); + QT_CLOSE(fd); + return false; } } @@ -254,11 +301,11 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) fh = 0; } else { - QByteArray fopenMode = openModeToFopenMode(openMode, nativeFilePath.constData()); + QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry, metaData); // Try to open the file in buffered mode. do { - fh = QT_FOPEN(nativeFilePath.constData(), fopenMode.constData()); + fh = QT_FOPEN(fileEntry.nativeFilePath().constData(), fopenMode.constData()); } while (!fh && errno == EINTR); // On failure, return and report the error. @@ -271,13 +318,11 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) if (!(openMode & QIODevice::WriteOnly)) { // we don't need this check if we tried to open for writing because then // we had received EISDIR anyway. - QT_STATBUF statBuf; - if (QT_FSTAT(fileno(fh), &statBuf) != -1) { - if ((statBuf.st_mode & S_IFMT) == S_IFDIR) { - q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); - fclose(fh); - return false; - } + if (QFileSystemEngine::fillMetaData(QT_FILENO(fh), metaData) + && metaData.isDirectory()) { + q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); + fclose(fh); + return false; } } @@ -303,6 +348,7 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) closeFileHandle = true; return true; } +#endif /*! \internal @@ -318,6 +364,10 @@ bool QFSFileEnginePrivate::nativeClose() */ bool QFSFileEnginePrivate::nativeFlush() { +#ifdef Q_OS_SYMBIAN + if (symbianFile.SubSessionHandle()) + return (KErrNone == symbianFile.Flush()); +#endif return fh ? flushFh() : fd != -1; } @@ -328,6 +378,24 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len) { Q_Q(QFSFileEngine); +#ifdef Q_OS_SYMBIAN + if (symbianFile.SubSessionHandle()) { + if(len > KMaxTInt) { + //this check is more likely to catch a corrupt length, since it isn't possible to allocate 2GB buffers (yet..) + q->setError(QFile::ReadError, QLatin1String("Maximum 2GB in single read on this platform")); + return -1; + } + TPtr8 ptr(reinterpret_cast<TUint8*>(data), static_cast<TInt>(len)); + TInt r = symbianFile.Read(symbianFilePos, ptr); + if (r != KErrNone) + { + q->setError(QFile::ReadError, QSystemError(r, QSystemError::NativeError).toString()); + return -1; + } + symbianFilePos += ptr.Length(); + return qint64(ptr.Length()); + } +#endif if (fh && nativeIsSequential()) { size_t readBytes = 0; int oldFlags = fcntl(QT_FILENO(fh), F_GETFL); @@ -395,6 +463,40 @@ qint64 QFSFileEnginePrivate::nativeReadLine(char *data, qint64 maxlen) */ qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len) { +#ifdef Q_OS_SYMBIAN + Q_Q(QFSFileEngine); + if (symbianFile.SubSessionHandle()) { + if(len > KMaxTInt) { + //this check is more likely to catch a corrupt length, since it isn't possible to allocate 2GB buffers (yet..) + q->setError(QFile::WriteError, QLatin1String("Maximum 2GB in single write on this platform")); + return -1; + } + const TPtrC8 ptr(reinterpret_cast<const TUint8*>(data), static_cast<TInt>(len)); +#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API + TInt64 eofpos = 0; +#else + TInt eofpos = 0; +#endif + //The end of file position is not cached because QFile is read/write sharable, therefore another + //process may have altered the file size. + TInt r = symbianFile.Seek(ESeekEnd, eofpos); + if (r == KErrNone && symbianFilePos > eofpos) { + //seek position is beyond end of file so file needs to be extended before write. + //note that SetSize does not zero-initialise (c.f. posix lseek) + r = symbianFile.SetSize(symbianFilePos); + } + if (r == KErrNone) { + //write to specific position in the file (i.e. use our own cursor rather than calling seek) + r = symbianFile.Write(symbianFilePos, ptr); + } + if (r != KErrNone) { + q->setError(QFile::WriteError, QSystemError(r, QSystemError::NativeError).toString()); + return -1; + } + symbianFilePos += len; + return len; + } +#endif return writeFdFh(data, len); } @@ -403,6 +505,12 @@ qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len) */ qint64 QFSFileEnginePrivate::nativePos() const { +#ifdef Q_OS_SYMBIAN + const Q_Q(QFSFileEngine); + if (symbianFile.SubSessionHandle()) { + return symbianFilePos; + } +#endif return posFdFh(); } @@ -411,6 +519,19 @@ qint64 QFSFileEnginePrivate::nativePos() const */ bool QFSFileEnginePrivate::nativeSeek(qint64 pos) { +#ifdef Q_OS_SYMBIAN + Q_Q(QFSFileEngine); + if (symbianFile.SubSessionHandle()) { +#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API + if(pos > KMaxTInt) { + q->setError(QFile::PositionError, QLatin1String("Maximum 2GB file position on this platform")); + return false; + } +#endif + symbianFilePos = pos; + return true; + } +#endif return seekFdFh(pos); } @@ -422,139 +543,110 @@ int QFSFileEnginePrivate::nativeHandle() const return fh ? fileno(fh) : fd; } +#ifdef Q_OS_SYMBIAN +int QFSFileEnginePrivate::getMapHandle() +{ + if (symbianFile.SubSessionHandle()) { + // Symbian file handle can't be used for open C mmap() so open the file with open C as well. + if (fileHandleForMaps < 0) { + int flags = openModeToOpenFlags(openMode); + flags &= ~(O_CREAT | O_TRUNC); + fileHandleForMaps = ::wopen((wchar_t*)(fileEntry.nativeFilePath().utf16()), flags, 0666); + } + return fileHandleForMaps; + } + return nativeHandle(); +} +#endif + /*! \internal */ bool QFSFileEnginePrivate::nativeIsSequential() const { +#ifdef Q_OS_SYMBIAN + if (symbianFile.SubSessionHandle()) + return false; +#endif return isSequentialFdFh(); } bool QFSFileEngine::remove() { Q_D(QFSFileEngine); - bool ret = unlink(d->nativeFilePath.constData()) == 0; - if (!ret) - setError(QFile::RemoveError, qt_error_string(errno)); + QSystemError error; + bool ret = QFileSystemEngine::removeFile(d->fileEntry, error); + d->metaData.clear(); + if (!ret) { + setError(QFile::RemoveError, error.toString()); + } return ret; } bool QFSFileEngine::copy(const QString &newName) { -#if defined(Q_OS_SYMBIAN) Q_D(QFSFileEngine); - RFs rfs = qt_s60GetRFs(); - CFileMan* fm = NULL; - QString oldNative(QDir::toNativeSeparators(d->filePath)); - TPtrC oldPtr(qt_QString2TPtrC(oldNative)); - QFileInfo fi(newName); - QString absoluteNewName = fi.absoluteFilePath(); - QString newNative(QDir::toNativeSeparators(absoluteNewName)); - TPtrC newPtr(qt_QString2TPtrC(newNative)); - TRAPD (err, - fm = CFileMan::NewL(rfs); - RFile rfile; - err = rfile.Open(rfs, oldPtr, EFileShareReadersOrWriters); - if (err == KErrNone) { - err = fm->Copy(rfile, newPtr); - rfile.Close(); - } - ) // End TRAP - delete fm; - if (err == KErrNone) - return true; - d->setSymbianError(err, QFile::CopyError, QLatin1String("copy error")); - return false; -#else - Q_UNUSED(newName); - // ### Add copy code for Unix here - setError(QFile::UnspecifiedError, QLatin1String("Not implemented!")); - return false; -#endif + QSystemError error; + bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(newName), error); + if (!ret) { + setError(QFile::CopyError, error.toString()); + } + return ret; } bool QFSFileEngine::rename(const QString &newName) { Q_D(QFSFileEngine); - bool ret = ::rename(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0; - if (!ret) - setError(QFile::RenameError, qt_error_string(errno)); + QSystemError error; + bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error); + + if (!ret) { + setError(QFile::RenameError, error.toString()); + } + return ret; } bool QFSFileEngine::link(const QString &newName) { Q_D(QFSFileEngine); - bool ret = ::symlink(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0; - if (!ret) - setError(QFile::RenameError, qt_error_string(errno)); + QSystemError error; + bool ret = QFileSystemEngine::createLink(d->fileEntry, QFileSystemEntry(newName), error); + if (!ret) { + setError(QFile::RenameError, error.toString()); + } return ret; } qint64 QFSFileEnginePrivate::nativeSize() const { +#ifdef Q_OS_SYMBIAN + const Q_Q(QFSFileEngine); + if (symbianFile.SubSessionHandle()) { +#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API + qint64 size; +#else + TInt size; +#endif + TInt err = symbianFile.Size(size); + if(err != KErrNone) { + const_cast<QFSFileEngine*>(q)->setError(QFile::PositionError, QSystemError(err, QSystemError::NativeError).toString()); + return 0; + } + return size; + } +#endif return sizeFdFh(); } bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const { - QString dirName = name; - if (createParentDirectories) { - dirName = QDir::cleanPath(dirName); -#if defined(Q_OS_SYMBIAN) - dirName = QDir::toNativeSeparators(dirName); -#endif - for(int oldslash = -1, slash=0; slash != -1; oldslash = slash) { - slash = dirName.indexOf(QDir::separator(), oldslash+1); - if (slash == -1) { - if (oldslash == dirName.length()) - break; - slash = dirName.length(); - } - if (slash) { - QByteArray chunk = QFile::encodeName(dirName.left(slash)); - QT_STATBUF st; - if (QT_STAT(chunk, &st) != -1) { - if ((st.st_mode & S_IFMT) != S_IFDIR) - return false; - } else if (QT_MKDIR(chunk, 0777) != 0) { - return false; - } - } - } - return true; - } -#if defined(Q_OS_DARWIN) // Mac X doesn't support trailing /'s - if (dirName.endsWith(QLatin1Char('/'))) - dirName.chop(1); -#endif - return (QT_MKDIR(QFile::encodeName(dirName), 0777) == 0); + return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories); } bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const { - QString dirName = name; - if (recurseParentDirectories) { - dirName = QDir::cleanPath(dirName); -#if defined(Q_OS_SYMBIAN) - dirName = QDir::toNativeSeparators(dirName); -#endif - for(int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) { - QByteArray chunk = QFile::encodeName(dirName.left(slash)); - QT_STATBUF st; - if (QT_STAT(chunk, &st) != -1) { - if ((st.st_mode & S_IFMT) != S_IFDIR) - return false; - if (::rmdir(chunk) != 0) - return oldslash != 0; - } else { - return false; - } - slash = dirName.lastIndexOf(QDir::separator(), oldslash-1); - } - return true; - } - return ::rmdir(QFile::encodeName(dirName)) == 0; + return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories); } bool QFSFileEngine::caseSensitive() const @@ -568,94 +660,27 @@ bool QFSFileEngine::caseSensitive() const bool QFSFileEngine::setCurrentPath(const QString &path) { - int r; - r = QT_CHDIR(QFile::encodeName(path)); - return r >= 0; + return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path)); } QString QFSFileEngine::currentPath(const QString &) { - QString result; - QT_STATBUF st; -#if defined(Q_OS_SYMBIAN) - char nativeCurrentName[PATH_MAX+1]; - if (::getcwd(nativeCurrentName, PATH_MAX)) - result = QDir::fromNativeSeparators(QFile::decodeName(QByteArray(nativeCurrentName))); - if (result.isEmpty()) { -# if defined(QT_DEBUG) - qWarning("QFSFileEngine::currentPath: getcwd() failed"); -# endif - } else -#endif - if (QT_STAT(".", &st) == 0) { -#if defined(__GLIBC__) && !defined(PATH_MAX) - char *currentName = ::get_current_dir_name(); - if (currentName) { - result = QFile::decodeName(QByteArray(currentName)); - ::free(currentName); - } -#elif !defined(Q_OS_SYMBIAN) - char currentName[PATH_MAX+1]; - if (::getcwd(currentName, PATH_MAX)) - result = QFile::decodeName(QByteArray(currentName)); -# if defined(QT_DEBUG) - if (result.isNull()) - qWarning("QFSFileEngine::currentPath: getcwd() failed"); -# endif -#endif - } else { -#if defined(Q_OS_SYMBIAN) - // If current dir returned by Open C doesn't exist, - // try to create it (can happen with application private dirs) - // Ignore mkdir failures; we want to be consistent with Open C - // current path regardless. - QT_MKDIR(QFile::encodeName(QLatin1String(nativeCurrentName)), 0777); -#else -# if defined(QT_DEBUG) - qWarning("QFSFileEngine::currentPath: stat(\".\") failed"); -# endif -#endif - } - return result; + return QFileSystemEngine::currentPath().filePath(); } QString QFSFileEngine::homePath() { -#if defined(Q_OS_SYMBIAN) - QString home = rootPath(); -#else - QString home = QFile::decodeName(qgetenv("HOME")); - if (home.isNull()) - home = rootPath(); -#endif - return home; + return QFileSystemEngine::homePath(); } QString QFSFileEngine::rootPath() { -#if defined(Q_OS_SYMBIAN) - TFileName symbianPath = PathInfo::PhoneMemoryRootPath(); - return QDir::cleanPath(QDir::fromNativeSeparators(qt_TDesC2QString(symbianPath))); -#else - return QLatin1String("/"); -#endif + return QFileSystemEngine::rootPath(); } QString QFSFileEngine::tempPath() { -#if defined(Q_OS_SYMBIAN) - TFileName symbianPath = PathInfo::PhoneMemoryRootPath(); - QString temp = QDir::fromNativeSeparators(qt_TDesC2QString(symbianPath)); - temp += QLatin1String( "temp/"); - - // Just to verify that folder really exist on hardware - QT_MKDIR(QFile::encodeName(temp), 0777); -#else - QString temp = QFile::decodeName(qgetenv("TMPDIR")); - if (temp.isEmpty()) - temp = QLatin1String("/tmp/"); -#endif - return temp; + return QFileSystemEngine::tempPath(); } QFileInfoList QFSFileEngine::drives() @@ -683,123 +708,30 @@ QFileInfoList QFSFileEngine::drives() return ret; } -bool QFSFileEnginePrivate::doStat() const +bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const { - if (!tried_stat) { - tried_stat = true; - could_stat = false; - - if (fh && nativeFilePath.isEmpty()) { - // ### actually covers two cases: d->fh and when the file is not open - could_stat = (QT_FSTAT(QT_FILENO(fh), &st) == 0); - } else if (fd == -1) { - // ### actually covers two cases: d->fh and when the file is not open -#if defined(Q_OS_SYMBIAN) - // Optimization for Symbian where fileFlags() calls both doStat() and isSymlink(), but rarely on real links. - // When the filename is not a link, lstat will return the same info as stat, but this also removes - // any need for a further call to lstat to check if the file is a link. - need_lstat = false; - could_stat = (QT_LSTAT(nativeFilePath.constData(), &st) == 0); - is_link = could_stat ? S_ISLNK(st.st_mode) : false; - // if it turns out this was a link, we can call stat too. - if (is_link) -#endif - could_stat = (QT_STAT(nativeFilePath.constData(), &st) == 0); - } else { - could_stat = (QT_FSTAT(fd, &st) == 0); - } - } - return could_stat; -} + if (!tried_stat || !metaData.hasFlags(flags)) { + tried_stat = 1; -bool QFSFileEnginePrivate::isSymlink() const -{ - if (need_lstat) { - need_lstat = false; + int localFd = fd; + if (fh && fileEntry.isEmpty()) + localFd = QT_FILENO(fh); + if (localFd != -1) + QFileSystemEngine::fillMetaData(localFd, metaData); - QT_STATBUF st; // don't clobber our main one - is_link = (QT_LSTAT(nativeFilePath.constData(), &st) == 0) ? S_ISLNK(st.st_mode) : false; + if (metaData.missingFlags(flags) && !fileEntry.isEmpty()) + QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags)); } - return is_link; -} -#if defined(Q_OS_SYMBIAN) -static bool _q_isSymbianHidden(const QString &path, bool isDir) -{ - RFs rfs = qt_s60GetRFs(); - QFileInfo fi(path); - QString absPath = fi.absoluteFilePath(); - if (isDir && !absPath.endsWith(QLatin1Char('/'))) - absPath.append(QLatin1Char('/')); - QString native(QDir::toNativeSeparators(absPath)); - TPtrC ptr(qt_QString2TPtrC(native)); - TUint attributes; - TInt err = rfs.Att(ptr, attributes); - return (err == KErrNone && (attributes & KEntryAttHidden)); -} -#endif - -#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) -static bool _q_isMacHidden(const QString &path) -{ - OSErr err = noErr; - - FSRef fsRef; - - err = FSPathMakeRefWithOptions(reinterpret_cast<const UInt8 *>(QFile::encodeName(QDir::cleanPath(path)).constData()), - kFSPathMakeRefDoNotFollowLeafSymlink, &fsRef, 0); - if (err != noErr) - return false; - - FSCatalogInfo catInfo; - err = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL); - if (err != noErr) - return false; - - FileInfo * const fileInfo = reinterpret_cast<FileInfo*>(&catInfo.finderInfo); - bool result = (fileInfo->finderFlags & kIsInvisible); - return result; + return metaData.exists(); } -#endif -QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFileEngine::FileFlags type) const +bool QFSFileEnginePrivate::isSymlink() const { - QAbstractFileEngine::FileFlags ret = 0; - - if (st.st_mode & S_IRUSR) - ret |= QAbstractFileEngine::ReadOwnerPerm; - if (st.st_mode & S_IWUSR) - ret |= QAbstractFileEngine::WriteOwnerPerm; - if (st.st_mode & S_IXUSR) - ret |= QAbstractFileEngine::ExeOwnerPerm; - if (st.st_mode & S_IRGRP) - ret |= QAbstractFileEngine::ReadGroupPerm; - if (st.st_mode & S_IWGRP) - ret |= QAbstractFileEngine::WriteGroupPerm; - if (st.st_mode & S_IXGRP) - ret |= QAbstractFileEngine::ExeGroupPerm; - if (st.st_mode & S_IROTH) - ret |= QAbstractFileEngine::ReadOtherPerm; - if (st.st_mode & S_IWOTH) - ret |= QAbstractFileEngine::WriteOtherPerm; - if (st.st_mode & S_IXOTH) - ret |= QAbstractFileEngine::ExeOtherPerm; - - // calculate user permissions - if (type & QAbstractFileEngine::ReadUserPerm) { - if (QT_ACCESS(nativeFilePath.constData(), R_OK) == 0) - ret |= QAbstractFileEngine::ReadUserPerm; - } - if (type & QAbstractFileEngine::WriteUserPerm) { - if (QT_ACCESS(nativeFilePath.constData(), W_OK) == 0) - ret |= QAbstractFileEngine::WriteUserPerm; - } - if (type & QAbstractFileEngine::ExeUserPerm) { - if (QT_ACCESS(nativeFilePath.constData(), X_OK) == 0) - ret |= QAbstractFileEngine::ExeUserPerm; - } + if (!metaData.hasFlags(QFileSystemMetaData::LinkType)) + QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::LinkType); - return ret; + return metaData.isLink(); } /*! @@ -808,364 +740,111 @@ QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFil QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const { Q_D(const QFSFileEngine); - // Force a stat, so that we're guaranteed to get up-to-date results - if (type & Refresh) { - d->tried_stat = 0; - d->need_lstat = 1; - } + + if (type & Refresh) + d->metaData.clear(); QAbstractFileEngine::FileFlags ret = 0; + if (type & FlagsMask) ret |= LocalDiskFlag; - bool exists = d->doStat(); - if (!exists && !d->isSymlink()) + + bool exists; + { + QFileSystemMetaData::MetaDataFlags queryFlags = 0; + + queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type)) + & QFileSystemMetaData::Permissions; + + if (type & TypesMask) + queryFlags |= QFileSystemMetaData::AliasType + | QFileSystemMetaData::LinkType + | QFileSystemMetaData::FileType + | QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::BundleType; + + if (type & FlagsMask) + queryFlags |= QFileSystemMetaData::HiddenAttribute + | QFileSystemMetaData::ExistsAttribute; + + queryFlags |= QFileSystemMetaData::LinkType; + + exists = d->doStat(queryFlags); + } + + if (!exists && !d->metaData.isLink()) return ret; if (exists && (type & PermsMask)) - ret |= d->getPermissions(type); + ret |= FileFlags(uint(d->metaData.permissions())); + if (type & TypesMask) { -#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) - bool foundAlias = false; - { - FSRef fref; - if (FSPathMakeRef((const UInt8 *)QFile::encodeName(QDir::cleanPath(d->filePath)).data(), - &fref, NULL) == noErr) { - Boolean isAlias, isFolder; - if (FSIsAliasFile(&fref, &isAlias, &isFolder) == noErr && isAlias) { - foundAlias = true; - ret |= LinkType; - } - } - } - if (!foundAlias) -#endif - { - if ((type & LinkType) && d->isSymlink()) + if (d->metaData.isAlias()) { + ret |= LinkType; + } else { + if ((type & LinkType) && d->metaData.isLink()) ret |= LinkType; - if (exists && (d->st.st_mode & S_IFMT) == S_IFREG) - ret |= FileType; - 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)) { - QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(d->filePath), - kCFURLPOSIXPathStyle, true); - UInt32 type, creator; - if (CFBundleGetPackageInfoInDirectory(url, &type, &creator)) - ret |= BundleType; + if (exists) { + if (d->metaData.isFile()) { + ret |= FileType; + } else if (d->metaData.isDirectory()) { + ret |= DirectoryType; + if ((type & BundleType) && d->metaData.isBundle()) + ret |= BundleType; + } } -#endif } } + if (type & FlagsMask) { if (exists) ret |= ExistsFlag; -#if defined(Q_OS_SYMBIAN) - if (d->filePath == QLatin1String("/") - || (d->filePath.length() == 3 && d->filePath.at(0).isLetter() - && d->filePath.at(1) == QLatin1Char(':') && d->filePath.at(2) == QLatin1Char('/'))) { + if (d->fileEntry.isRoot()) ret |= RootFlag; - } else { - // In Symbian, all symlinks have hidden attribute for some reason; - // lets make them visible for better compatibility with other platforms. - // If somebody actually wants a hidden link, then they are out of luck. - if (!d->isSymlink() && _q_isSymbianHidden(d->filePath, ret & DirectoryType)) - ret |= HiddenFlag; - } -#else - if (d->filePath == QLatin1String("/")) { - ret |= RootFlag; - } else { - QString baseName = fileName(BaseName); - if ((baseName.size() > 0 && baseName.at(0) == QLatin1Char('.')) -# if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) - || _q_isMacHidden(d->filePath) -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - || d->st.st_flags & UF_HIDDEN -# endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 -# endif - ) { - ret |= HiddenFlag; - } - } -#endif + else if (d->metaData.isHidden()) + ret |= HiddenFlag; } - return ret; -} - -#if defined(Q_OS_SYMBIAN) -QString QFSFileEngine::fileName(FileName file) const -{ - Q_D(const QFSFileEngine); - const QLatin1Char slashChar('/'); - if(file == BaseName) { - int slash = d->filePath.lastIndexOf(slashChar); - if(slash == -1) { - int colon = d->filePath.lastIndexOf(QLatin1Char(':')); - 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()) - return d->filePath; - - int slash = d->filePath.lastIndexOf(slashChar); - if(slash == -1) { - if(d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) - return d->filePath.left(2); - return QLatin1String("."); - } else { - if(!slash) - return QLatin1String("/"); - if(slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) - slash++; - return d->filePath.left(slash); - } - } else if(file == AbsoluteName || file == AbsolutePathName) { - QString ret; - if (!isRelativePathSymbian(d->filePath)) { - if (d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') - && d->filePath.at(2) != slashChar){ - // It's a drive-relative path, so C:a.txt -> C:/currentpath/a.txt, - // or if it's different drive than current, Z:a.txt -> Z:/a.txt - QString currentPath = QDir::currentPath(); - if (0 == currentPath.left(1).compare(d->filePath.left(1), Qt::CaseInsensitive)) - ret = currentPath + slashChar + d->filePath.mid(2); - else - ret = d->filePath.left(2) + slashChar + d->filePath.mid(2); - } else if (d->filePath.startsWith(slashChar)) { - // It's a absolute path to the current drive, so /a.txt -> C:/a.txt - ret = QDir::currentPath().left(2) + d->filePath; - } else { - ret = d->filePath; - } - } else { - ret = QDir::currentPath() + slashChar + d->filePath; - } - - // The path should be absolute at this point. - // From the docs : - // Absolute paths begin with the directory separator "/" - // (optionally preceded by a drive specification under Windows). - if (ret.at(0) != slashChar) { - Q_ASSERT(ret.length() >= 2); - Q_ASSERT(ret.at(0).isLetter()); - Q_ASSERT(ret.at(1) == QLatin1Char(':')); - - // Force uppercase drive letters. - ret[0] = ret.at(0).toUpper(); - } - - // Clean up the path - bool isDir = ret.endsWith(slashChar); - ret = QDir::cleanPath(ret); - if (isDir && !ret.endsWith(slashChar)) - ret += slashChar; - if (file == AbsolutePathName) { - int slash = ret.lastIndexOf(slashChar); - if (slash < 0) - return ret; - else if (ret.at(0) != slashChar && slash == 2) - return ret.left(3); // include the slash - else - return ret.left(slash > 0 ? slash : 1); - } - return ret; - } else if(file == CanonicalName || file == CanonicalPathName) { - if (!(fileFlags(ExistsFlag) & ExistsFlag)) - return QString(); - - QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName)); - if (file == CanonicalPathName && !ret.isEmpty()) { - int slash = ret.lastIndexOf(slashChar); - if (slash == -1) - ret = QDir::fromNativeSeparators(QDir::currentPath()); - else if (slash == 0) - ret = QLatin1String("/"); - ret = ret.left(slash); - } - return ret; - } else if(file == LinkName) { - if (d->isSymlink()) { - char s[PATH_MAX+1]; - int len = readlink(d->nativeFilePath.constData(), s, PATH_MAX); - if (len > 0) { - s[len] = '\0'; - QString ret = QFile::decodeName(QByteArray(s)); - - if (isRelativePathSymbian(ret)) { - if (!isRelativePathSymbian(d->filePath)) { - ret.prepend(d->filePath.left(d->filePath.lastIndexOf(slashChar)) - + slashChar); - } else { - ret.prepend(QDir::currentPath() + slashChar); - } - } - ret = QDir::cleanPath(ret); - if (ret.size() > 1 && ret.endsWith(slashChar)) - ret.chop(1); - return ret; - } - } - return QString(); - } else if(file == BundleName) { - return QString(); - } - return d->filePath; + return ret; } -#else - QString QFSFileEngine::fileName(FileName file) const { Q_D(const QFSFileEngine); if (file == BundleName) { -#if !defined(QWS) && defined(Q_OS_MAC) - QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(d->filePath), - kCFURLPOSIXPathStyle, true); - if (QCFType<CFDictionaryRef> dict = CFBundleCopyInfoDictionaryForURL(url)) { - if (CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) { - if (CFGetTypeID(name) == CFStringGetTypeID()) - return QCFString::toQString((CFStringRef)name); - } - } -#endif - return QString(); + return QFileSystemEngine::bundleName(d->fileEntry); } else if (file == BaseName) { - int slash = d->filePath.lastIndexOf(QLatin1Char('/')); - if (slash != -1) - return d->filePath.mid(slash + 1); + return d->fileEntry.fileName(); } else if (file == PathName) { - int slash = d->filePath.lastIndexOf(QLatin1Char('/')); - if (slash == -1) - return QLatin1String("."); - else if (!slash) - return QLatin1String("/"); - return d->filePath.left(slash); + return d->fileEntry.path(); } else if (file == AbsoluteName || file == AbsolutePathName) { - QString ret; - if (d->filePath.isEmpty() || !d->filePath.startsWith(QLatin1Char('/'))) - ret = QDir::currentPath(); - if (!d->filePath.isEmpty() && d->filePath != QLatin1String(".")) { - if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/'))) - ret += QLatin1Char('/'); - ret += d->filePath; - } - if (ret == QLatin1String("/")) - return ret; - bool isDir = ret.endsWith(QLatin1Char('/')); - ret = QDir::cleanPath(ret); - if (isDir) - ret += QLatin1Char('/'); + QFileSystemEntry entry(QFileSystemEngine::absoluteName(d->fileEntry)); if (file == AbsolutePathName) { - int slash = ret.lastIndexOf(QLatin1Char('/')); - if (slash == -1) - return QDir::currentPath(); - else if (!slash) - return QLatin1String("/"); - return ret.left(slash); + return entry.path(); } - return ret; + return entry.filePath(); } else if (file == CanonicalName || file == CanonicalPathName) { - if (!(fileFlags(ExistsFlag) & ExistsFlag)) - return QString(); - - QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName)); - if (file == CanonicalPathName && !ret.isEmpty()) { - int slash = ret.lastIndexOf(QLatin1Char('/')); - if (slash == -1) - ret = QDir::currentPath(); - else if (slash == 0) - ret = QLatin1String("/"); - ret = ret.left(slash); - } - return ret; + QFileSystemEntry entry(QFileSystemEngine::canonicalName(d->fileEntry, d->metaData)); + if (file == CanonicalPathName) + return entry.path(); + return entry.filePath(); } else if (file == LinkName) { if (d->isSymlink()) { -#if defined(__GLIBC__) && !defined(PATH_MAX) -#define PATH_CHUNK_SIZE 256 - char *s = 0; - int len = -1; - int size = PATH_CHUNK_SIZE; - - while (1) { - s = (char *) ::realloc(s, size); - Q_CHECK_PTR(s); - len = ::readlink(d->nativeFilePath.constData(), s, size); - if (len < 0) { - ::free(s); - break; - } - if (len < size) { - break; - } - size *= 2; - } -#else - char s[PATH_MAX+1]; - int len = readlink(d->nativeFilePath.constData(), s, PATH_MAX); -#endif - if (len > 0) { - QString ret; - if (d->doStat() && S_ISDIR(d->st.st_mode) && s[0] != '/') { - QDir parent(d->filePath); - parent.cdUp(); - ret = parent.path(); - if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/'))) - ret += QLatin1Char('/'); - } - s[len] = '\0'; - ret += QFile::decodeName(QByteArray(s)); -#if defined(__GLIBC__) && !defined(PATH_MAX) - ::free(s); -#endif - - if (!ret.startsWith(QLatin1Char('/'))) { - if (d->filePath.startsWith(QLatin1Char('/'))) { - ret.prepend(d->filePath.left(d->filePath.lastIndexOf(QLatin1Char('/'))) - + QLatin1Char('/')); - } else { - ret.prepend(QDir::currentPath() + QLatin1Char('/')); - } - } - ret = QDir::cleanPath(ret); - if (ret.size() > 1 && ret.endsWith(QLatin1Char('/'))) - ret.chop(1); - return ret; - } - } -#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) - { - FSRef fref; - if (FSPathMakeRef((const UInt8 *)QFile::encodeName(QDir::cleanPath(d->filePath)).data(), &fref, 0) == noErr) { - Boolean isAlias, isFolder; - if (FSResolveAliasFile(&fref, true, &isFolder, &isAlias) == noErr && isAlias) { - AliasHandle alias; - if (FSNewAlias(0, &fref, &alias) == noErr && alias) { - QCFString cfstr; - if (FSCopyAliasInfo(alias, 0, 0, &cfstr, 0, 0) == noErr) - return QCFString::toQString(cfstr); - } - } - } + QFileSystemEntry entry = QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData); + return entry.filePath(); } -#endif return QString(); } - return d->filePath; + return d->fileEntry.filePath(); } -#endif // Q_OS_SYMBIAN bool QFSFileEngine::isRelativePath() const { Q_D(const QFSFileEngine); #if defined(Q_OS_SYMBIAN) - return isRelativePathSymbian(d->filePath); + return isRelativePathSymbian(d->fileEntry.filePath()); #else - return d->filePath.length() ? d->filePath[0] != QLatin1Char('/') : true; + return d->fileEntry.filePath().length() ? d->fileEntry.filePath()[0] != QLatin1Char('/') : true; #endif } @@ -1173,101 +852,73 @@ uint QFSFileEngine::ownerId(FileOwner own) const { Q_D(const QFSFileEngine); static const uint nobodyID = (uint) -2; - if (d->doStat()) { - if (own == OwnerUser) - return d->st.st_uid; - else - return d->st.st_gid; - } + + if (d->doStat(QFileSystemMetaData::OwnerIds)) + return d->metaData.ownerId(own); + return nobodyID; } QString QFSFileEngine::owner(FileOwner own) const { -#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) - int size_max = sysconf(_SC_GETPW_R_SIZE_MAX); - if (size_max == -1) - size_max = 1024; - QVarLengthArray<char, 1024> buf(size_max); -#endif - - if (own == OwnerUser) { - struct passwd *pw = 0; -#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) - struct passwd entry; - getpwuid_r(ownerId(own), &entry, buf.data(), buf.size(), &pw); -#else - pw = getpwuid(ownerId(own)); -#endif - if (pw) - return QFile::decodeName(QByteArray(pw->pw_name)); - } else if (own == OwnerGroup) { -#if !defined(Q_OS_SYMBIAN) - struct group *gr = 0; -#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) - size_max = sysconf(_SC_GETGR_R_SIZE_MAX); - if (size_max == -1) - size_max = 1024; - buf.resize(size_max); - struct group entry; - // Some large systems have more members than the POSIX max size - // Loop over by doubling the buffer size (upper limit 250k) - for (unsigned size = size_max; size < 256000; size += size) - { - buf.resize(size); - // ERANGE indicates that the buffer was too small - if (!getgrgid_r(ownerId(own), &entry, buf.data(), buf.size(), &gr) - || errno != ERANGE) - break; - } +#ifndef Q_OS_SYMBIAN + if (own == OwnerUser) + return QFileSystemEngine::resolveUserName(ownerId(own)); + return QFileSystemEngine::resolveGroupName(ownerId(own)); #else - gr = getgrgid(ownerId(own)); -#endif - if (gr) - return QFile::decodeName(QByteArray(gr->gr_name)); -#endif - } return QString(); +#endif } bool QFSFileEngine::setPermissions(uint perms) { Q_D(QFSFileEngine); + QSystemError error; + if (!QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error, 0)) { + setError(QFile::PermissionsError, error.toString()); + return false; + } + return true; +} + +#ifdef Q_OS_SYMBIAN +bool QFSFileEngine::setSize(qint64 size) +{ + Q_D(QFSFileEngine); bool ret = false; - mode_t mode = 0; - if (perms & ReadOwnerPerm) - mode |= S_IRUSR; - if (perms & WriteOwnerPerm) - mode |= S_IWUSR; - if (perms & ExeOwnerPerm) - mode |= S_IXUSR; - if (perms & ReadUserPerm) - mode |= S_IRUSR; - if (perms & WriteUserPerm) - mode |= S_IWUSR; - if (perms & ExeUserPerm) - mode |= S_IXUSR; - if (perms & ReadGroupPerm) - mode |= S_IRGRP; - if (perms & WriteGroupPerm) - mode |= S_IWGRP; - if (perms & ExeGroupPerm) - mode |= S_IXGRP; - if (perms & ReadOtherPerm) - mode |= S_IROTH; - if (perms & WriteOtherPerm) - mode |= S_IWOTH; - if (perms & ExeOtherPerm) - mode |= S_IXOTH; - if (d->fd != -1) - ret = fchmod(d->fd, mode) == 0; - else - ret = ::chmod(d->nativeFilePath.constData(), mode) == 0; - if (!ret) - setError(QFile::PermissionsError, qt_error_string(errno)); + TInt err = KErrNone; + if (d->symbianFile.SubSessionHandle()) { + TInt err = d->symbianFile.SetSize(size); + ret = (err == KErrNone); + if (ret && d->symbianFilePos > size) + d->symbianFilePos = size; + } + else if (d->fd != -1) + ret = QT_FTRUNCATE(d->fd, size) == 0; + else if (d->fh) + ret = QT_FTRUNCATE(QT_FILENO(d->fh), size) == 0; + else { + RFile tmp; + QString symbianFilename(d->fileEntry.nativeFilePath()); + err = tmp.Open(qt_s60GetRFs(), qt_QString2TPtrC(symbianFilename), EFileWrite); + if (err == KErrNone) + { + err = tmp.SetSize(size); + tmp.Close(); + } + ret = (err == KErrNone); + } + if (!ret) { + QSystemError error; + if (err) + error = QSystemError(err, QSystemError::NativeError); + else + error = QSystemError(errno, QSystemError::StandardLibraryError); + setError(QFile::ResizeError, error.toString()); + } return ret; } - +#else bool QFSFileEngine::setSize(qint64 size) { Q_D(QFSFileEngine); @@ -1277,25 +928,21 @@ bool QFSFileEngine::setSize(qint64 size) else if (d->fh) ret = QT_FTRUNCATE(QT_FILENO(d->fh), size) == 0; else - ret = QT_TRUNCATE(d->nativeFilePath.constData(), size) == 0; + ret = QT_TRUNCATE(d->fileEntry.nativeFilePath().constData(), size) == 0; if (!ret) setError(QFile::ResizeError, qt_error_string(errno)); return ret; } +#endif QDateTime QFSFileEngine::fileTime(FileTime time) const { Q_D(const QFSFileEngine); - QDateTime ret; - if (d->doStat()) { - if (time == CreationTime) - ret.setTime_t(d->st.st_ctime ? d->st.st_ctime : d->st.st_mtime); - else if (time == ModificationTime) - ret.setTime_t(d->st.st_mtime); - else if (time == AccessTime) - ret.setTime_t(d->st.st_atime); - } - return ret; + + if (d->doStat(QFileSystemMetaData::Times)) + return d->metaData.fileTime(time); + + return QDateTime(); } uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags) @@ -1315,8 +962,8 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla // If we know the mapping will extend beyond EOF, fail early to avoid // undefined behavior. Otherwise, let mmap have its say. - if (doStat() - && (QT_OFF_T(size) > st.st_size - QT_OFF_T(offset))) + if (doStat(QFileSystemMetaData::SizeAttribute) + && (QT_OFF_T(size) > metaData.size() - QT_OFF_T(offset))) qWarning("QFSFileEngine::map: Mapping a file beyond its size is not portable"); int access = 0; @@ -1338,7 +985,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla #ifdef Q_OS_SYMBIAN void *mapAddress; TRAPD(err, mapAddress = QT_MMAP((void*)0, realSize, - access, MAP_SHARED, nativeHandle(), realOffset)); + access, MAP_SHARED, getMapHandle(), realOffset)); if (err != KErrNone) { qWarning("OpenC bug: leave from mmap %d", err); mapAddress = MAP_FAILED; diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 71b10b4..3b6e80c 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -43,7 +43,7 @@ #include "qplatformdefs.h" #include "qabstractfileengine.h" #include "private/qfsfileengine_p.h" -#include <private/qsystemlibrary_p.h> +#include "qfilesystemengine_p.h" #include <qdebug.h> #include "qfile.h" @@ -69,239 +69,12 @@ #define SECURITY_WIN32 #include <security.h> -#ifndef SPI_GETPLATFORMTYPE -#define SPI_GETPLATFORMTYPE 257 -#endif - #ifndef PATH_MAX #define PATH_MAX FILENAME_MAX #endif -#ifndef _INTPTR_T_DEFINED -#ifdef _WIN64 -typedef __int64 intptr_t; -#else -#ifdef _W64 -typedef _W64 int intptr_t; -#else -typedef INT_PTR intptr_t; -#endif -#endif -#define _INTPTR_T_DEFINED -#endif - -#ifndef INVALID_FILE_ATTRIBUTES -# define INVALID_FILE_ATTRIBUTES (DWORD (-1)) -#endif - -#if !defined(Q_OS_WINCE) -# if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) -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) -# endif // !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) - -# ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE -# define MAXIMUM_REPARSE_DATA_BUFFER_SIZE 16384 -# endif -# ifndef IO_REPARSE_TAG_SYMLINK -# define IO_REPARSE_TAG_SYMLINK (0xA000000CL) -# endif -# ifndef FSCTL_GET_REPARSE_POINT -# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) -# endif -#endif // !defined(Q_OS_WINCE) - QT_BEGIN_NAMESPACE -static QString readLink(const QString &link); - -Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0; - -#if defined(Q_OS_WINCE) -static QString qfsPrivateCurrentDir = QLatin1String(""); -// As none of the functions we try to resolve do exist on Windows CE -// we use QT_NO_LIBRARY to shorten everything up a little bit. -#define QT_NO_LIBRARY 1 -#endif - -#if !defined(QT_NO_LIBRARY) -QT_BEGIN_INCLUDE_NAMESPACE -typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); -static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0; -typedef BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE); -static PtrLookupAccountSidW ptrLookupAccountSidW = 0; -typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID); -static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0; -typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK); -static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0; -static TRUSTEE_W currentUserTrusteeW; -static TRUSTEE_W worldTrusteeW; - -typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD); -static PtrGetUserProfileDirectoryW ptrGetUserProfileDirectoryW = 0; -typedef BOOL (WINAPI *PtrGetVolumePathNamesForVolumeNameW)(LPCWSTR,LPWSTR,DWORD,PDWORD); -static PtrGetVolumePathNamesForVolumeNameW ptrGetVolumePathNamesForVolumeNameW = 0; -QT_END_INCLUDE_NAMESPACE - - -void QFSFileEnginePrivate::resolveLibs() -{ - 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; -#if !defined(Q_OS_WINCE) - HINSTANCE advapiHnd = QSystemLibrary::load(L"advapi32"); - if (advapiHnd) { - ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW"); - ptrLookupAccountSidW = (PtrLookupAccountSidW)GetProcAddress(advapiHnd, "LookupAccountSidW"); - ptrBuildTrusteeWithSidW = (PtrBuildTrusteeWithSidW)GetProcAddress(advapiHnd, "BuildTrusteeWithSidW"); - ptrGetEffectiveRightsFromAclW = (PtrGetEffectiveRightsFromAclW)GetProcAddress(advapiHnd, "GetEffectiveRightsFromAclW"); - } - if (ptrBuildTrusteeWithSidW) { - // Create TRUSTEE for current user - HANDLE hnd = ::GetCurrentProcess(); - HANDLE token = 0; - if (::OpenProcessToken(hnd, TOKEN_QUERY, &token)) { - TOKEN_USER tu; - DWORD retsize; - if (::GetTokenInformation(token, TokenUser, &tu, sizeof(tu), &retsize)) - ptrBuildTrusteeWithSidW(¤tUserTrusteeW, tu.User.Sid); - ::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) { - // 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); - } - } - HINSTANCE userenvHnd = QSystemLibrary::load(L"userenv"); - if (userenvHnd) - ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW"); - HINSTANCE kernel32 = LoadLibrary(L"kernel32"); - if(kernel32) - ptrGetVolumePathNamesForVolumeNameW = (PtrGetVolumePathNamesForVolumeNameW)GetProcAddress(kernel32, "GetVolumePathNamesForVolumeNameW"); -#endif - } -} -#endif // QT_NO_LIBRARY - -typedef DWORD (WINAPI *PtrNetShareEnum)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD); -static PtrNetShareEnum ptrNetShareEnum = 0; -typedef DWORD (WINAPI *PtrNetApiBufferFree)(LPVOID); -static PtrNetApiBufferFree ptrNetApiBufferFree = 0; -typedef struct _SHARE_INFO_1 { - LPWSTR shi1_netname; - DWORD shi1_type; - LPWSTR shi1_remark; -} SHARE_INFO_1; - - -bool QFSFileEnginePrivate::resolveUNCLibs() -{ - static bool triedResolve = false; - if (!triedResolve) { -#ifndef QT_NO_THREAD - QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); - if (triedResolve) { - return ptrNetShareEnum && ptrNetApiBufferFree; - } -#endif - triedResolve = true; -#if !defined(Q_OS_WINCE) - HINSTANCE hLib = QSystemLibrary::load(L"Netapi32"); - if (hLib) { - ptrNetShareEnum = (PtrNetShareEnum)GetProcAddress(hLib, "NetShareEnum"); - if (ptrNetShareEnum) - ptrNetApiBufferFree = (PtrNetApiBufferFree)GetProcAddress(hLib, "NetApiBufferFree"); - } -#endif - } - return ptrNetShareEnum && ptrNetApiBufferFree; -} - -bool QFSFileEnginePrivate::uncListSharesOnServer(const QString &server, QStringList *list) -{ - if (resolveUNCLibs()) { - SHARE_INFO_1 *BufPtr, *p; - DWORD res; - 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) { - p = BufPtr; - for (i = 1; i <= er; ++i) { - if (list && p->shi1_type == 0) - list->append(QString::fromWCharArray(p->shi1_netname)); - p++; - } - } - ptrNetApiBufferFree(BufPtr); - } while (res == ERROR_MORE_DATA); - return res == ERROR_SUCCESS; - } - return false; -} - -static bool isUncRoot(const QString &server) -{ - QString localPath = QDir::toNativeSeparators(server); - if (!localPath.startsWith(QLatin1String("\\\\"))) - return false; - - int idx = localPath.indexOf(QLatin1Char('\\'), 2); - if (idx == -1 || idx + 1 == localPath.length()) - return true; - - localPath = localPath.right(localPath.length() - idx - 1).trimmed(); - return localPath.isEmpty(); -} - #if !defined(Q_OS_WINCE) static inline bool isUncPath(const QString &path) { @@ -311,73 +84,6 @@ static inline bool isUncPath(const QString &path) } #endif -static inline bool isRelativePath(const QString &path) -{ - // drive, e.g. "a:", or UNC root, e.q. "//" - return !(path.startsWith(QLatin1Char('/')) - || (path.length() >= 2 - && ((path.at(0).isLetter() && path.at(1) == QLatin1Char(':')) - || (path.at(0) == QLatin1Char('/') && path.at(1) == QLatin1Char('/'))))); -} - -static QString fixIfRelativeUncPath(const QString &path) -{ - if (isRelativePath(path)) { - QString currentPath = QDir::currentPath() + QLatin1Char('/'); - if (currentPath.startsWith(QLatin1String("//"))) - return QString(path).prepend(currentPath); - } - return path; -} - -// can be //server or //server/share -static bool uncShareExists(const QString &server) -{ - QStringList parts = server.split(QLatin1Char('\\'), QString::SkipEmptyParts); - if (parts.count()) { - QStringList shares; - if (QFSFileEnginePrivate::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(0), &shares)) - return parts.count() >= 2 ? shares.contains(parts.at(1), Qt::CaseInsensitive) : true; - } - return false; -} - -static inline bool isDriveRoot(const QString &path) -{ - return (path.length() == 3 - && path.at(0).isLetter() && path.at(1) == QLatin1Char(':') - && path.at(2) == QLatin1Char('/')); -} - -static QString nativeAbsoluteFilePath(const QString &path) -{ - QString absPath; -#if !defined(Q_OS_WINCE) - QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1)); - wchar_t *fileName = 0; - DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName); - if (retLen > (DWORD)buf.size()) { - buf.resize(retLen); - retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName); - } - if (retLen != 0) - absPath = QString::fromWCharArray(buf.data(), retLen); -#else - if (path.startsWith(QLatin1Char('/')) || path.startsWith(QLatin1Char('\\'))) - absPath = QDir::toNativeSeparators(path); - else - absPath = QDir::toNativeSeparators(QDir::cleanPath(qfsPrivateCurrentDir + QLatin1Char('/') + path)); -#endif - // This is really ugly, but GetFullPathName strips off whitespace at the end. - // If you for instance write ". " in the lineedit of QFileDialog, - // (which is an invalid filename) this function will strip the space off and viola, - // the file is later reported as existing. Therefore, we re-add the whitespace that - // was at the end of path in order to keep the filename invalid. - if (!path.isEmpty() && path.at(path.size() - 1) == QLatin1Char(' ')) - absPath.append(QLatin1Char(' ')); - return absPath; -} - /*! \internal */ @@ -386,7 +92,7 @@ QString QFSFileEnginePrivate::longFileName(const QString &path) if (path.startsWith(QLatin1String("\\\\.\\"))) return path; - QString absPath = nativeAbsoluteFilePath(path); + QString absPath = QFileSystemEngine::nativeAbsoluteFilePath(path); #if !defined(Q_OS_WINCE) QString prefix = QLatin1String("\\\\?\\"); if (isUncPath(absPath)) { @@ -402,15 +108,6 @@ QString QFSFileEnginePrivate::longFileName(const QString &path) /* \internal */ -void QFSFileEnginePrivate::nativeInitFileName() -{ - QString path = longFileName(QDir::toNativeSeparators(fixIfRelativeUncPath(filePath))); - nativeFilePath = QByteArray((const char *)path.utf16(), path.size() * 2 + 1); -} - -/* - \internal -*/ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) { Q_Q(QFSFileEngine); @@ -428,9 +125,8 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) // WriteOnly can create files, ReadOnly cannot. DWORD creationDisp = (openMode & QIODevice::WriteOnly) ? OPEN_ALWAYS : OPEN_EXISTING; - // Create the file handle. - fileHandle = CreateFile((const wchar_t*)nativeFilePath.constData(), + fileHandle = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(), accessRights, shareMode, &securityAtts, @@ -520,17 +216,9 @@ qint64 QFSFileEnginePrivate::nativeSize() const // ### Don't flush; for buffered files, we should get away with ftell. thatQ->flush(); -#if !defined(Q_OS_WINCE) - // stdlib/stdio mode. - if (fh || fd != -1) { - qint64 fileSize = _filelengthi64(fh ? QT_FILENO(fh) : fd); - if (fileSize == -1) { - fileSize = 0; - thatQ->setError(QFile::UnspecifiedError, qt_error_string(errno)); - } - return fileSize; - } -#else // Q_OS_WINCE + // Always retrive the current information + metaData.clearFlags(QFileSystemMetaData::SizeAttribute); +#if defined(Q_OS_WINCE) // Buffered stdlib mode. if (fh) { QT_OFF_T oldPos = QT_FTELL(fh); @@ -543,70 +231,22 @@ qint64 QFSFileEnginePrivate::nativeSize() const } return fileSize; } -#endif - - // Not-open mode, where the file name is known: We'll check the - // file system directly. - if (openMode == QIODevice::NotOpen && !nativeFilePath.isEmpty()) { - WIN32_FILE_ATTRIBUTE_DATA attribData; - bool ok = ::GetFileAttributesEx((const wchar_t*)nativeFilePath.constData(), - GetFileExInfoStandard, &attribData); - if (!ok) { - int errorCode = GetLastError(); - if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { - QByteArray path = nativeFilePath; - // path for the FindFirstFile should not end with a trailing slash - while (!path.isEmpty() && reinterpret_cast<const wchar_t *>( - path.constData() + path.length())[-1] == '\\') - path.chop(2); - - // FindFirstFile can not handle drives - if (!path.isEmpty() && reinterpret_cast<const wchar_t *>( - path.constData() + path.length())[-1] != ':') { - WIN32_FIND_DATA findData; - HANDLE hFind = ::FindFirstFile((const wchar_t*)path.constData(), - &findData); - if (hFind != INVALID_HANDLE_VALUE) { - ::FindClose(hFind); - ok = true; - attribData.nFileSizeHigh = findData.nFileSizeHigh; - attribData.nFileSizeLow = findData.nFileSizeLow; - } - } - } - } - if (ok) { - qint64 size = attribData.nFileSizeHigh; - size <<= 32; - size += attribData.nFileSizeLow; - return size; - } - thatQ->setError(QFile::UnspecifiedError, qt_error_string()); - return 0; - } - -#if defined(Q_OS_WINCE) - // Unbuffed stdio mode if (fd != -1) { thatQ->setError(QFile::UnspecifiedError, QLatin1String("Not implemented!")); return 0; } #endif + bool filled = false; + if (fileHandle != INVALID_HANDLE_VALUE && openMode != QIODevice::NotOpen ) + filled = QFileSystemEngine::fillMetaData(fileHandle, metaData, + QFileSystemMetaData::SizeAttribute); + else + filled = doStat(QFileSystemMetaData::SizeAttribute); - // Windows native mode. - if (fileHandle == INVALID_HANDLE_VALUE) - return 0; - - BY_HANDLE_FILE_INFORMATION fileInfo; - if (!GetFileInformationByHandle(fileHandle, &fileInfo)) { - thatQ->setError(QFile::UnspecifiedError, qt_error_string()); - return 0; + if (!filled) { + thatQ->setError(QFile::UnspecifiedError, qt_error_string(errno)); } - - qint64 size = fileInfo.nFileSizeHigh; - size <<= 32; - size += fileInfo.nFileSizeLow; - return size; + return metaData.size(); } /* @@ -840,159 +480,41 @@ bool QFSFileEnginePrivate::nativeIsSequential() const bool QFSFileEngine::remove() { Q_D(QFSFileEngine); - bool ret = ::DeleteFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16()) != 0; + QSystemError error; + bool ret = QFileSystemEngine::removeFile(d->fileEntry, error); if (!ret) - setError(QFile::RemoveError, qt_error_string()); + setError(QFile::RemoveError, error.toString()); return ret; } bool QFSFileEngine::copy(const QString ©Name) { Q_D(QFSFileEngine); - bool ret = ::CopyFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), - (wchar_t*)QFSFileEnginePrivate::longFileName(copyName).utf16(), true) != 0; + QSystemError error; + bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(copyName), error); if (!ret) - setError(QFile::CopyError, qt_error_string()); + setError(QFile::CopyError, error.toString()); return ret; } bool QFSFileEngine::rename(const QString &newName) { Q_D(QFSFileEngine); - bool ret = ::MoveFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), - (wchar_t*)QFSFileEnginePrivate::longFileName(newName).utf16()) != 0; + QSystemError error; + bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error); if (!ret) - setError(QFile::RenameError, qt_error_string()); + setError(QFile::RenameError, error.toString()); return ret; } -static inline bool mkDir(const QString &path) -{ -#if defined(Q_OS_WINCE) - // Unfortunately CreateDirectory returns true for paths longer than - // 256, but does not create a directory. It starts to fail, when - // path length > MAX_PATH, which is 260 usually on CE. - // This only happens on a Windows Mobile device. Windows CE seems - // not to be affected by this. - static int platformId = 0; - if (platformId == 0) { - wchar_t platformString[64]; - if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(platformString)/sizeof(*platformString),platformString,0)) { - if (0 == wcscmp(platformString, L"PocketPC") || 0 == wcscmp(platformString, L"Smartphone")) - platformId = 1; - else - platformId = 2; - } - } - if (platformId == 1 && QFSFileEnginePrivate::longFileName(path).size() > 256) - return false; -#endif - return ::CreateDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), 0); -} - -static inline bool rmDir(const QString &path) -{ - return ::RemoveDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); -} - -static bool isDirPath(const QString &dirPath, bool *existed) -{ - QString path = dirPath; - if (path.length() == 2 && path.at(1) == QLatin1Char(':')) - path += QLatin1Char('\\'); - - DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); - if (fileAttrib == INVALID_FILE_ATTRIBUTES) { - int errorCode = GetLastError(); - if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { - // path for the FindFirstFile should not end with a trailing slash - while (path.endsWith(QLatin1Char('\\'))) - path.chop(1); - - // FindFirstFile can not handle drives - if (!path.endsWith(QLatin1Char(':'))) { - WIN32_FIND_DATA findData; - HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), - &findData); - if (hFind != INVALID_HANDLE_VALUE) { - ::FindClose(hFind); - fileAttrib = findData.dwFileAttributes; - } - } - } - } - - if (existed) - *existed = fileAttrib != INVALID_FILE_ATTRIBUTES; - - if (fileAttrib == INVALID_FILE_ATTRIBUTES) - return false; - - return fileAttrib & FILE_ATTRIBUTE_DIRECTORY; -} - bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const { - QString dirName = name; - if (createParentDirectories) { - dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); - // We spefically search for / so \ would break it.. - int oldslash = -1; - if (dirName.startsWith(QLatin1String("\\\\"))) { - // Don't try to create the root path of a UNC path; - // CreateDirectory() will just return ERROR_INVALID_NAME. - for (int i = 0; i < dirName.size(); ++i) { - if (dirName.at(i) != QDir::separator()) { - oldslash = i; - break; - } - } - if (oldslash != -1) - oldslash = dirName.indexOf(QDir::separator(), oldslash); - } - for (int slash=0; slash != -1; oldslash = slash) { - slash = dirName.indexOf(QDir::separator(), oldslash+1); - if (slash == -1) { - if (oldslash == dirName.length()) - break; - slash = dirName.length(); - } - if (slash) { - QString chunk = dirName.left(slash); - bool existed = false; - if (!isDirPath(chunk, &existed)) { - if (!existed) { - if (!mkDir(chunk)) - return false; - } else { - return false; - } - } - } - } - return true; - } - return mkDir(name); + return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories); } bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const { - QString dirName = name; - if (recurseParentDirectories) { - dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); - for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) { - QString chunk = dirName.left(slash); - if (chunk.length() == 2 && chunk.at(0).isLetter() && chunk.at(1) == QLatin1Char(':')) - break; - if (!isDirPath(chunk, 0)) - return false; - if (!rmDir(chunk)) - return oldslash != 0; - slash = dirName.lastIndexOf(QDir::separator(), oldslash-1); - } - return true; - } - return rmDir(name); + return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories); } bool QFSFileEngine::caseSensitive() const @@ -1002,15 +524,7 @@ bool QFSFileEngine::caseSensitive() const bool QFSFileEngine::setCurrentPath(const QString &path) { - if (!QDir(path).exists()) - return false; - -#if !defined(Q_OS_WINCE) - return ::SetCurrentDirectory((wchar_t*)path.utf16()) != 0; -#else - qfsPrivateCurrentDir = QFSFileEnginePrivate::longFileName(path); - return true; -#endif + return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path)); } QString QFSFileEngine::currentPath(const QString &fileName) @@ -1029,115 +543,30 @@ QString QFSFileEngine::currentPath(const QString &fileName) } if (ret.isEmpty()) { //just the pwd - DWORD size = 0; - wchar_t currentName[PATH_MAX]; - size = ::GetCurrentDirectory(PATH_MAX, currentName); - if (size != 0) { - if (size > PATH_MAX) { - wchar_t *newCurrentName = new wchar_t[size]; - if (::GetCurrentDirectory(PATH_MAX, newCurrentName) != 0) - ret = QString::fromWCharArray(newCurrentName); - delete [] newCurrentName; - } else { - ret = QString::fromWCharArray(currentName); - } - } + ret = QFileSystemEngine::currentPath().filePath(); } if (ret.length() >= 2 && ret[1] == QLatin1Char(':')) ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters. - return QDir::fromNativeSeparators(ret); + return ret; #else Q_UNUSED(fileName); - if (qfsPrivateCurrentDir.isEmpty()) - qfsPrivateCurrentDir = QCoreApplication::applicationDirPath(); - - return QDir::fromNativeSeparators(qfsPrivateCurrentDir); + return QFileSystemEngine::currentPath(); #endif } QString QFSFileEngine::homePath() { - QString ret; -#if !defined(QT_NO_LIBRARY) - QFSFileEnginePrivate::resolveLibs(); - if (ptrGetUserProfileDirectoryW) { - HANDLE hnd = ::GetCurrentProcess(); - HANDLE token = 0; - BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token); - if (ok) { - DWORD dwBufferSize = 0; - // First call, to determine size of the strings (with '\0'). - ok = ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize); - if (!ok && dwBufferSize != 0) { // We got the required buffer size - wchar_t *userDirectory = new wchar_t[dwBufferSize]; - // Second call, now we can fill the allocated buffer. - ok = ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize); - if (ok) - ret = QString::fromWCharArray(userDirectory); - - delete [] userDirectory; - } - ::CloseHandle(token); - } - } -#endif - if (ret.isEmpty() || !QFile::exists(ret)) { - ret = QString::fromLocal8Bit(qgetenv("USERPROFILE").constData()); - if (ret.isEmpty() || !QFile::exists(ret)) { - ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE").constData()) + QString::fromLocal8Bit(qgetenv("HOMEPATH").constData()); - if (ret.isEmpty() || !QFile::exists(ret)) { - ret = QString::fromLocal8Bit(qgetenv("HOME").constData()); - if (ret.isEmpty() || !QFile::exists(ret)) { -#if defined(Q_OS_WINCE) - ret = QLatin1String("\\My Documents"); - if (!QFile::exists(ret)) -#endif - ret = rootPath(); - } - } - } - } - return QDir::fromNativeSeparators(ret); + return QFileSystemEngine::homePath(); } QString QFSFileEngine::rootPath() { -#if defined(Q_OS_WINCE) - QString ret = QLatin1String("/"); -#elif defined(Q_FS_FAT) - QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData()); - if (ret.isEmpty()) - ret = QLatin1String("c:"); - ret.append(QLatin1Char('/')); -#elif defined(Q_OS_OS2EMX) - char dir[4]; - _abspath(dir, QLatin1String("/"), _MAX_PATH); - QString ret(dir); -#endif - return ret; + return QFileSystemEngine::rootPath(); } QString QFSFileEngine::tempPath() { - 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 = QLatin1String("c:/tmp"); -#else - ret = QLatin1String("/Temp"); -#endif - } - return ret; + return QFileSystemEngine::tempPath(); } QFileInfoList QFSFileEngine::drives() @@ -1167,232 +596,25 @@ QFileInfoList QFSFileEngine::drives() #endif } -bool QFSFileEnginePrivate::doStat() const +bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const { - if (!tried_stat) { + if (!tried_stat || !metaData.hasFlags(flags)) { tried_stat = true; - could_stat = false; - - if (filePath.isEmpty()) - return could_stat; - - QString fname; - if(filePath.endsWith(QLatin1String(".lnk"))) { - fname = readLink(filePath); - if(fname.isEmpty()) - return could_stat; - } - else - fname = filePath; - fname = fixIfRelativeUncPath(fname); - - UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); - - if (fd != -1) { -#if !defined(Q_OS_WINCE) - HANDLE fh = (HANDLE)_get_osfhandle(fd); - if (fh != INVALID_HANDLE_VALUE) { - BY_HANDLE_FILE_INFORMATION fileInfo; - if (GetFileInformationByHandle(fh, &fileInfo)) { - could_stat = true; - fileAttrib = fileInfo.dwFileAttributes; - } - } -#else - DWORD tmpAttributes = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16()); - if (tmpAttributes != -1) { - fileAttrib = tmpAttributes; - could_stat = true; - } -#endif - } else { - fileAttrib = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16()); - if (fileAttrib == INVALID_FILE_ATTRIBUTES) { - int errorCode = GetLastError(); - if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { - QString path = QDir::toNativeSeparators(fname); - // path for the FindFirstFile should not end with a trailing slash - while (path.endsWith(QLatin1Char('\\'))) - path.chop(1); - - // FindFirstFile can not handle drives - if (!path.endsWith(QLatin1Char(':'))) { - WIN32_FIND_DATA findData; - HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), - &findData); - if (hFind != INVALID_HANDLE_VALUE) { - ::FindClose(hFind); - fileAttrib = findData.dwFileAttributes; - } - } - } - } - could_stat = fileAttrib != INVALID_FILE_ATTRIBUTES; - if (!could_stat) { #if !defined(Q_OS_WINCE) - if (isDriveRoot(fname)) { - // a valid drive ?? - DWORD drivesBitmask = ::GetLogicalDrives(); - int drivebit = 1 << (fname.at(0).toUpper().unicode() - QLatin1Char('A').unicode()); - if (drivesBitmask & drivebit) { - fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM; - could_stat = true; - } - } else { + int localFd = fd; + if (fh && fileEntry.isEmpty()) + localFd = QT_FILENO(fh); + if (localFd != -1) + QFileSystemEngine::fillMetaData(localFd, metaData, flags); #endif - QString path = QDir::toNativeSeparators(fname); - bool is_dir = false; - if (path.startsWith(QLatin1String("\\\\"))) { - // UNC - stat doesn't work for all cases (Windows bug) - int s = path.indexOf(path.at(0),2); - if (s > 0) { - // "\\server\..." - s = path.indexOf(path.at(0),s+1); - if (s > 0) { - // "\\server\share\..." - if (s == path.size() - 1) { - // "\\server\share\" - is_dir = true; - } else { - // "\\server\share\notfound" - } - } else { - // "\\server\share" - is_dir = true; - } - } else { - // "\\server" - is_dir = true; - } - } - if (is_dir && uncShareExists(path)) { - // looks like a UNC dir, is a dir. - fileAttrib = FILE_ATTRIBUTE_DIRECTORY; - could_stat = true; - } -#if !defined(Q_OS_WINCE) - } -#endif - } - } - - SetErrorMode(oldmode); + if (metaData.missingFlags(flags) && !fileEntry.isEmpty()) + QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags)); } - 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 if (rdb->ReparseTag == IO_REPARSE_TAG_SYMLINK) { - 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); - -#if !defined(QT_NO_LIBRARY) - QFSFileEnginePrivate::resolveLibs(); - if (ptrGetVolumePathNamesForVolumeNameW) { - QRegExp matchVolName(QLatin1String("^Volume\\{([a-z]|[0-9]|-)+\\}\\\\"), Qt::CaseInsensitive); - if(matchVolName.indexIn(result) == 0) { - DWORD len; - wchar_t buffer[MAX_PATH]; - QString volumeName = result.mid(0, matchVolName.matchedLength()).prepend(QLatin1String("\\\\?\\")); - if(ptrGetVolumePathNamesForVolumeNameW((wchar_t*)volumeName.utf16(), buffer, MAX_PATH, &len) != 0) - result.replace(0,matchVolName.matchedLength(), QString::fromWCharArray(buffer)); - } - } -#endif - } -#else - Q_UNUSED(link); -#endif // Q_OS_WINCE - return result; + return metaData.exists(); } -static QString readLink(const QString &link) -{ -#if !defined(Q_OS_WINCE) -#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS) - QString ret; - - bool neededCoInit = false; - IShellLink *psl; // pointer to IShellLink i/f - WIN32_FIND_DATA wfd; - wchar_t szGotPath[MAX_PATH]; - - // Get pointer to the IShellLink interface. - HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl); - - if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized - neededCoInit = true; - CoInitialize(NULL); - hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - IID_IShellLink, (LPVOID *)&psl); - } - if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface. - IPersistFile *ppf; - hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); - 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 (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR) - ret = QString::fromWCharArray(szGotPath); - } - ppf->Release(); - } - psl->Release(); - } - if (neededCoInit) - CoUninitialize(); - - return ret; -#else - Q_UNUSED(link); - return QString(); -#endif // QT_NO_LIBRARY -#else - wchar_t target[MAX_PATH]; - QString result; - if (SHGetShortcutTarget((wchar_t*)QFileInfo(link).absoluteFilePath().replace(QLatin1Char('/'),QLatin1Char('\\')).utf16(), target, MAX_PATH)) { - result = QString::fromWCharArray(target); - if (result.startsWith(QLatin1Char('"'))) - result.remove(0,1); - if (result.endsWith(QLatin1Char('"'))) - result.remove(result.size()-1,1); - } - return result; -#endif // Q_OS_WINCE -} bool QFSFileEngine::link(const QString &newName) { @@ -1457,191 +679,63 @@ bool QFSFileEngine::link(const QString &newName) #endif // Q_OS_WINCE } -QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFileEngine::FileFlags type) const +/*! + \reimp +*/ +QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const { + Q_D(const QFSFileEngine); + + if (type & Refresh) + d->metaData.clear(); + QAbstractFileEngine::FileFlags ret = 0; -#if !defined(QT_NO_LIBRARY) - if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) { - resolveLibs(); - if(ptrGetNamedSecurityInfoW && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW) { - enum { ReadMask = 0x00000001, WriteMask = 0x00000002, ExecMask = 0x00000020 }; - - QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; - PSID pOwner = 0; - PSID pGroup = 0; - PACL pDacl; - PSECURITY_DESCRIPTOR pSD; - DWORD res = ptrGetNamedSecurityInfoW((wchar_t*)fname.utf16(), SE_FILE_OBJECT, - OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, - &pOwner, &pGroup, &pDacl, 0, &pSD); - if(res == ERROR_SUCCESS) { - ACCESS_MASK access_mask; - TRUSTEE_W trustee; - if (type & 0x0700) { // user - if(ptrGetEffectiveRightsFromAclW(pDacl, ¤tUserTrusteeW, &access_mask) != ERROR_SUCCESS) - access_mask = (ACCESS_MASK)-1; - if(access_mask & ReadMask) - ret |= QAbstractFileEngine::ReadUserPerm; - if(access_mask & WriteMask) - ret |= QAbstractFileEngine::WriteUserPerm; - if(access_mask & ExecMask) - ret |= QAbstractFileEngine::ExeUserPerm; - } - if (type & 0x7000) { // owner - ptrBuildTrusteeWithSidW(&trustee, pOwner); - if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) - access_mask = (ACCESS_MASK)-1; - if(access_mask & ReadMask) - ret |= QAbstractFileEngine::ReadOwnerPerm; - if(access_mask & WriteMask) - ret |= QAbstractFileEngine::WriteOwnerPerm; - if(access_mask & ExecMask) - ret |= QAbstractFileEngine::ExeOwnerPerm; - } - if (type & 0x0070) { // group - ptrBuildTrusteeWithSidW(&trustee, pGroup); - if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) - access_mask = (ACCESS_MASK)-1; - if(access_mask & ReadMask) - ret |= QAbstractFileEngine::ReadGroupPerm; - if(access_mask & WriteMask) - ret |= QAbstractFileEngine::WriteGroupPerm; - if(access_mask & ExecMask) - ret |= QAbstractFileEngine::ExeGroupPerm; - } - if (type & 0x0007) { // other (world) - if(ptrGetEffectiveRightsFromAclW(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS) - access_mask = (ACCESS_MASK)-1; // ### - if(access_mask & ReadMask) - ret |= QAbstractFileEngine::ReadOtherPerm; - if(access_mask & WriteMask) - ret |= QAbstractFileEngine::WriteOtherPerm; - if(access_mask & ExecMask) - ret |= QAbstractFileEngine::ExeOtherPerm; - } - LocalFree(pSD); - } - } - } else -#endif + if (type & FlagsMask) + ret |= LocalDiskFlag; + + bool exists; { - //### what to do with permissions if we don't use NTFS - // for now just add all permissions and what about exe missions ?? - // also qt_ntfs_permission_lookup is now not set by default ... should it ? - ret |= QAbstractFileEngine::ReadOwnerPerm | QAbstractFileEngine::ReadGroupPerm - | QAbstractFileEngine::ReadOtherPerm; - - if (!(fileAttrib & FILE_ATTRIBUTE_READONLY)) { - ret |= QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteGroupPerm - | QAbstractFileEngine::WriteOtherPerm; - } + QFileSystemMetaData::MetaDataFlags queryFlags = 0; - QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; - QString ext = fname.right(4).toLower(); - if ((fileAttrib & FILE_ATTRIBUTE_DIRECTORY) || - ext == QLatin1String(".exe") || ext == QLatin1String(".com") || ext == QLatin1String(".bat") || - ext == QLatin1String(".pif") || ext == QLatin1String(".cmd")) { - ret |= QAbstractFileEngine::ExeOwnerPerm | QAbstractFileEngine::ExeGroupPerm - | QAbstractFileEngine::ExeOtherPerm | QAbstractFileEngine::ExeUserPerm; - } + queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type)) + & QFileSystemMetaData::Permissions; - // calculate user permissions - if (type & QAbstractFileEngine::ReadUserPerm) { - if (::_waccess((wchar_t*)longFileName(fname).utf16(), R_OK) == 0) - ret |= QAbstractFileEngine::ReadUserPerm; - } - if (type & QAbstractFileEngine::WriteUserPerm) { - if (::_waccess((wchar_t*)longFileName(fname).utf16(), W_OK) == 0) - ret |= QAbstractFileEngine::WriteUserPerm; - } - } - return ret; -} + // AliasType and BundleType are 0x0 + if (type & TypesMask) + queryFlags |= QFileSystemMetaData::AliasType + | QFileSystemMetaData::LinkType + | QFileSystemMetaData::FileType + | QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::BundleType; -/*! - \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_SYMLINK || findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) { - is_link = true; - } - } - } - } - return is_link; -#else - return false; -#endif // Q_OS_WINCE -} + if (type & FlagsMask) + queryFlags |= QFileSystemMetaData::HiddenAttribute + | QFileSystemMetaData::ExistsAttribute; -/*! - \reimp -*/ -QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const -{ - Q_D(const QFSFileEngine); - QAbstractFileEngine::FileFlags ret = 0; - // 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 - } + queryFlags |= QFileSystemMetaData::LinkType; - if (type & PermsMask) { - if (d->doStat()) { - ret |= ExistsFlag; - ret |= d->getPermissions(type); - } + exists = d->doStat(queryFlags); } + + if (exists && (type & PermsMask)) + ret |= FileFlags(uint(d->metaData.permissions())); + if (type & TypesMask) { - if (d->filePath.endsWith(QLatin1String(".lnk"))) { + if ((type & LinkType) && d->metaData.isLegacyLink()) ret |= LinkType; - QString l = readLink(d->filePath); - if (!l.isEmpty()) { - bool existed = false; - if (isDirPath(l, &existed) && existed) - ret |= DirectoryType; - else if (existed) - ret |= FileType; - } - } else if (d->doStat()) { - if ((type & LinkType) && d->isSymlink()) - ret |= LinkType; - if (d->fileAttrib & FILE_ATTRIBUTE_DIRECTORY) { - ret |= DirectoryType; - } else { - ret |= FileType; - } + if (d->metaData.isDirectory()) { + ret |= DirectoryType; + } else { + ret |= FileType; } } if (type & FlagsMask) { - ret |= LocalDiskFlag; - if (d->doStat()) { + if (d->metaData.exists()) { ret |= ExistsFlag; - if (d->filePath == QLatin1String("/") || isDriveRoot(d->filePath) || isUncRoot(d->filePath)) + if (d->fileEntry.isRoot()) ret |= RootFlag; - else if (d->fileAttrib & FILE_ATTRIBUTE_HIDDEN) + else if (d->metaData.isHidden()) ret |= HiddenFlag; } } @@ -1652,50 +746,28 @@ QString QFSFileEngine::fileName(FileName file) const { Q_D(const QFSFileEngine); if (file == BaseName) { - int slash = d->filePath.lastIndexOf(QLatin1Char('/')); - if (slash == -1) { - int colon = d->filePath.lastIndexOf(QLatin1Char(':')); - if (colon != -1) - return d->filePath.mid(colon + 1); - return d->filePath; - } - return d->filePath.mid(slash + 1); + return d->fileEntry.fileName(); } 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(':')) - return d->filePath.left(2); - return QString(QLatin1Char('.')); - } else { - if (!slash) - return QString(QLatin1Char('/')); - if (slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) - slash++; - return d->filePath.left(slash); - } + return d->fileEntry.path(); } else if (file == AbsoluteName || file == AbsolutePathName) { QString ret; if (!isRelativePath()) { #if !defined(Q_OS_WINCE) - if (d->filePath.startsWith(QLatin1Char('/')) || // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt - d->filePath.size() == 2 || // It's a drive letter that needs to get a working dir appended - (d->filePath.size() > 2 && d->filePath.at(2) != QLatin1Char('/')) || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt - d->filePath.contains(QLatin1String("/../")) || d->filePath.contains(QLatin1String("/./")) || - d->filePath.endsWith(QLatin1String("/..")) || d->filePath.endsWith(QLatin1String("/."))) + if (d->fileEntry.filePath().startsWith(QLatin1Char('/')) || // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt + d->fileEntry.filePath().size() == 2 || // It's a drive letter that needs to get a working dir appended + (d->fileEntry.filePath().size() > 2 && d->fileEntry.filePath().at(2) != QLatin1Char('/')) || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt + d->fileEntry.filePath().contains(QLatin1String("/../")) || d->fileEntry.filePath().contains(QLatin1String("/./")) || + d->fileEntry.filePath().endsWith(QLatin1String("/..")) || d->fileEntry.filePath().endsWith(QLatin1String("/."))) { - ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(d->filePath)); - } else { - ret = d->filePath; - } -#else - ret = d->filePath; + ret = QDir::fromNativeSeparators(QFileSystemEngine::nativeAbsoluteFilePath(d->fileEntry.filePath())); + } else #endif + { + ret = d->fileEntry.filePath(); + } } else { - ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->filePath); + ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->fileEntry.filePath()); } // The path should be absolute at this point. @@ -1724,38 +796,24 @@ QString QFSFileEngine::fileName(FileName file) const } else if (file == CanonicalName || file == CanonicalPathName) { if (!(fileFlags(ExistsFlag) & ExistsFlag)) return QString(); + QFileSystemEntry entry(QFileSystemEngine::canonicalName(QFileSystemEntry(fileName(AbsoluteName)), d->metaData)); - QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName)); - if (!ret.isEmpty() && file == CanonicalPathName) { - int slash = ret.lastIndexOf(QLatin1Char('/')); - if (slash == -1) - ret = QDir::currentPath(); - else if (slash == 0) - ret = QString(QLatin1Char('/')); - ret = ret.left(slash); - } - return ret; + if (file == CanonicalPathName) + return entry.path(); + return entry.filePath(); } 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); + return QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData).filePath(); } else if (file == BundleName) { return QString(); } - return d->filePath; + return d->fileEntry.filePath(); } bool QFSFileEngine::isRelativePath() const { Q_D(const QFSFileEngine); // drive, e.g. "a:", or UNC root, e.q. "//" - return !(d->filePath.startsWith(QLatin1Char('/')) - || (d->filePath.length() >= 2 - && ((d->filePath.at(0).isLetter() && d->filePath.at(1) == QLatin1Char(':')) - || (d->filePath.at(0) == QLatin1Char('/') && d->filePath.at(1) == QLatin1Char('/'))))); + return d->fileEntry.isRelative(); } uint QFSFileEngine::ownerId(FileOwner /*own*/) const @@ -1766,69 +824,17 @@ uint QFSFileEngine::ownerId(FileOwner /*own*/) const QString QFSFileEngine::owner(FileOwner own) const { - QString name; -#if !defined(QT_NO_LIBRARY) Q_D(const QFSFileEngine); - if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) { - QFSFileEnginePrivate::resolveLibs(); - if (ptrGetNamedSecurityInfoW && ptrLookupAccountSidW) { - PSID pOwner = 0; - PSECURITY_DESCRIPTOR pSD; - if (ptrGetNamedSecurityInfoW((wchar_t*)d->filePath.utf16(), SE_FILE_OBJECT, - own == OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION, - own == OwnerUser ? &pOwner : 0, own == OwnerGroup ? &pOwner : 0, - 0, 0, &pSD) == ERROR_SUCCESS) { - DWORD lowner = 64; - DWORD ldomain = 64; - QVarLengthArray<wchar_t, 64> owner(lowner); - QVarLengthArray<wchar_t, 64> domain(ldomain); - SID_NAME_USE use = SidTypeUnknown; - // First call, to determine size of the strings (with '\0'). - if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner, - (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) { - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - if (lowner > (DWORD)owner.size()) - owner.resize(lowner); - if (ldomain > (DWORD)domain.size()) - domain.resize(ldomain); - // Second call, try on resized buf-s - if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner, - (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) { - lowner = 0; - } - } else { - lowner = 0; - } - } - if (lowner != 0) - name = QString::fromWCharArray(owner.data()); - LocalFree(pSD); - } - } - } -#else - Q_UNUSED(own); -#endif - return name; + return QFileSystemEngine::owner(d->fileEntry, own); } bool QFSFileEngine::setPermissions(uint perms) { Q_D(QFSFileEngine); - bool ret = false; - int mode = 0; - - if (perms & QFile::ReadOwner || perms & QFile::ReadUser || perms & QFile::ReadGroup || perms & QFile::ReadOther) - mode |= _S_IREAD; - if (perms & QFile::WriteOwner || perms & QFile::WriteUser || perms & QFile::WriteGroup || perms & QFile::WriteOther) - mode |= _S_IWRITE; - - if (mode == 0) // not supported - return false; - - ret = ::_wchmod((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), mode) == 0; + QSystemError error; + bool ret = QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error); if (!ret) - setError(QFile::PermissionsError, qt_error_string(errno)); + setError(QFile::PermissionsError, error.toString()); return ret; } @@ -1836,12 +842,16 @@ bool QFSFileEngine::setSize(qint64 size) { Q_D(QFSFileEngine); - if (d->fileHandle != INVALID_HANDLE_VALUE || d->fd != -1) { + if (d->fileHandle != INVALID_HANDLE_VALUE || d->fd != -1 || d->fh) { // resize open file HANDLE fh = d->fileHandle; #if !defined(Q_OS_WINCE) - if (fh == INVALID_HANDLE_VALUE) - fh = (HANDLE)_get_osfhandle(d->fd); + if (fh == INVALID_HANDLE_VALUE) { + if (d->fh) + fh = (HANDLE)_get_osfhandle(QT_FILENO(d->fh)); + else + fh = (HANDLE)_get_osfhandle(d->fd); + } #endif if (fh == INVALID_HANDLE_VALUE) return false; @@ -1856,9 +866,9 @@ bool QFSFileEngine::setSize(qint64 size) return false; } - if (!d->nativeFilePath.isEmpty()) { + if (!d->fileEntry.isEmpty()) { // resize file on disk - QFile file(d->filePath); + QFile file(d->fileEntry.filePath()); if (file.open(QFile::ReadWrite)) { bool ret = file.resize(size); if (!ret) @@ -1870,94 +880,14 @@ bool QFSFileEngine::setSize(qint64 size) } -static inline QDateTime fileTimeToQDateTime(const FILETIME *time) -{ - QDateTime ret; - -#if defined(Q_OS_WINCE) - SYSTEMTIME systime; - FILETIME ftime; - systime.wYear = 1970; - systime.wMonth = 1; - systime.wDay = 1; - systime.wHour = 0; - systime.wMinute = 0; - systime.wSecond = 0; - systime.wMilliseconds = 0; - systime.wDayOfWeek = 4; - SystemTimeToFileTime(&systime, &ftime); - unsigned __int64 acttime = (unsigned __int64)time->dwHighDateTime << 32 | time->dwLowDateTime; - FileTimeToSystemTime(time, &systime); - unsigned __int64 time1970 = (unsigned __int64)ftime.dwHighDateTime << 32 | ftime.dwLowDateTime; - unsigned __int64 difftime = acttime - time1970; - difftime /= 10000000; - ret.setTime_t((unsigned int)difftime); -#else - SYSTEMTIME sTime, lTime; - FileTimeToSystemTime(time, &sTime); - SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime); - ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay)); - ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds)); -#endif - - return ret; -} - QDateTime QFSFileEngine::fileTime(FileTime time) const { Q_D(const QFSFileEngine); - QDateTime ret; - if (d->fd != -1) { -#if !defined(Q_OS_WINCE) - HANDLE fh = (HANDLE)_get_osfhandle(d->fd); - if (fh != INVALID_HANDLE_VALUE) { - FILETIME creationTime, lastAccessTime, lastWriteTime; - if (GetFileTime(fh, &creationTime, &lastAccessTime, &lastWriteTime)) { - if(time == CreationTime) - ret = fileTimeToQDateTime(&creationTime); - else if(time == ModificationTime) - ret = fileTimeToQDateTime(&lastWriteTime); - else if(time == AccessTime) - ret = fileTimeToQDateTime(&lastAccessTime); - } - } -#endif - } else { - WIN32_FILE_ATTRIBUTE_DATA attribData; - bool ok = ::GetFileAttributesEx((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), GetFileExInfoStandard, &attribData); - if (!ok) { - int errorCode = GetLastError(); - if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { - QString path = QDir::toNativeSeparators(d->filePath); - // path for the FindFirstFile should not end with a trailing slash - while (path.endsWith(QLatin1Char('\\'))) - path.chop(1); - - // FindFirstFile can not handle drives - if (!path.endsWith(QLatin1Char(':'))) { - WIN32_FIND_DATA findData; - HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), - &findData); - if (hFind != INVALID_HANDLE_VALUE) { - ::FindClose(hFind); - ok = true; - attribData.ftCreationTime = findData.ftCreationTime; - attribData.ftLastWriteTime = findData.ftLastWriteTime; - attribData.ftLastAccessTime = findData.ftLastAccessTime; - } - } - } - } - if (ok) { - if(time == CreationTime) - ret = fileTimeToQDateTime(&attribData.ftCreationTime); - else if(time == ModificationTime) - ret = fileTimeToQDateTime(&attribData.ftLastWriteTime); - else if(time == AccessTime) - ret = fileTimeToQDateTime(&attribData.ftLastAccessTime); - } - } - return ret; + + if (d->doStat(QFileSystemMetaData::Times)) + return d->metaData.fileTime(time); + + return QDateTime(); } uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, @@ -1986,7 +916,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, #ifdef Q_USE_DEPRECATED_MAP_API nativeClose(); // handle automatically closed by kernel with mapHandle (below). - handle = ::CreateFileForMapping((const wchar_t*)nativeFilePath.constData(), + handle = ::CreateFileForMapping((const wchar_t*)fileEntry.nativeFilePath().utf16(), GENERIC_READ | (openMode & QIODevice::WriteOnly ? GENERIC_WRITE : 0), 0, NULL, diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index c34c4a4..79dfa35 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -295,7 +295,7 @@ public: : QFSFileEngine(), filePathIsTemplate(fileIsTemplate) { Q_D(QFSFileEngine); - d->filePath = file; + d->fileEntry = QFileSystemEntry(file); if (!filePathIsTemplate) QFSFileEngine::setFileName(file); @@ -325,6 +325,9 @@ bool QTemporaryFileEngine::isReallyOpen() Q_D(QFSFileEngine); if (!((0 == d->fh) && (-1 == d->fd) +#if defined (Q_OS_SYMBIAN) + && (0 == d->symbianFile.SubSessionHandle()) +#endif #if defined Q_OS_WIN && (INVALID_HANDLE_VALUE == d->fileHandle) #endif @@ -346,7 +349,7 @@ void QTemporaryFileEngine::setFileTemplate(const QString &fileTemplate) { Q_D(QFSFileEngine); if (filePathIsTemplate) - d->filePath = fileTemplate; + d->fileEntry = QFileSystemEntry(fileTemplate); } bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) @@ -359,7 +362,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (!filePathIsTemplate) return QFSFileEngine::open(openMode); - QString qfilename = d->filePath; + QString qfilename = d->fileEntry.filePath(); if(!qfilename.contains(QLatin1String("XXXXXX"))) qfilename += QLatin1String(".XXXXXX"); @@ -377,9 +380,8 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) d->closeFileHandle = true; // Restore the file names (open() resets them). - d->filePath = QString::fromLocal8Bit(filename); //changed now! + d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename)); //note that filename is NOT a native path filePathIsTemplate = false; - d->nativeInitFileName(); delete [] filename; return true; } @@ -395,9 +397,8 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) return false; } - QString template_ = d->filePath; - d->filePath = QString::fromLocal8Bit(filename); - d->nativeInitFileName(); + QString template_ = d->fileEntry.filePath(); + d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename)); delete [] filename; if (QFSFileEngine::open(openMode)) { @@ -405,8 +406,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) return true; } - d->filePath = template_; - d->nativeFilePath.clear(); + d->fileEntry = QFileSystemEntry(template_); return false; #endif } @@ -418,7 +418,7 @@ bool QTemporaryFileEngine::remove() // we must explicitly call QFSFileEngine::close() before we remove it. QFSFileEngine::close(); if (QFSFileEngine::remove()) { - d->filePath.clear(); + d->fileEntry.clear(); return true; } return false; diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 1e27c31..93818d1 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -1,81 +1,83 @@ # Qt core object module HEADERS += \ - kernel/qabstracteventdispatcher.h \ + kernel/qabstracteventdispatcher.h \ kernel/qabstractitemmodel.h \ kernel/qabstractitemmodel_p.h \ - kernel/qbasictimer.h \ - kernel/qeventloop.h\ - kernel/qpointer.h \ + kernel/qbasictimer.h \ + kernel/qeventloop.h\ + kernel/qpointer.h \ kernel/qcorecmdlineargs_p.h \ - kernel/qcoreapplication.h \ - kernel/qcoreevent.h \ - kernel/qmetaobject.h \ - kernel/qmetatype.h \ - kernel/qmimedata.h \ - kernel/qobject.h \ - kernel/qobjectdefs.h \ - kernel/qsignalmapper.h \ - kernel/qsocketnotifier.h \ - kernel/qtimer.h \ - kernel/qtranslator.h \ + kernel/qcoreapplication.h \ + kernel/qcoreevent.h \ + kernel/qmetaobject.h \ + kernel/qmetatype.h \ + kernel/qmimedata.h \ + kernel/qobject.h \ + kernel/qobjectdefs.h \ + kernel/qsignalmapper.h \ + kernel/qsocketnotifier.h \ + kernel/qtimer.h \ + kernel/qtranslator.h \ kernel/qtranslator_p.h \ kernel/qvariant.h \ - kernel/qabstracteventdispatcher_p.h \ - kernel/qcoreapplication_p.h \ - kernel/qobjectcleanuphandler.h \ + kernel/qabstracteventdispatcher_p.h \ + kernel/qcoreapplication_p.h \ + kernel/qobjectcleanuphandler.h \ kernel/qvariant_p.h \ kernel/qmetaobject_p.h \ kernel/qobject_p.h \ - kernel/qcoreglobaldata_p.h \ - kernel/qsharedmemory.h \ + kernel/qcoreglobaldata_p.h \ + kernel/qsharedmemory.h \ kernel/qsharedmemory_p.h \ kernel/qsystemsemaphore.h \ kernel/qsystemsemaphore_p.h \ kernel/qfunctions_p.h \ - kernel/qmath.h + kernel/qmath.h \ + kernel/qsystemerror_p.h SOURCES += \ - kernel/qabstracteventdispatcher.cpp \ + kernel/qabstracteventdispatcher.cpp \ kernel/qabstractitemmodel.cpp \ - kernel/qbasictimer.cpp \ - kernel/qeventloop.cpp \ - kernel/qcoreapplication.cpp \ - kernel/qcoreevent.cpp \ - kernel/qmetaobject.cpp \ - kernel/qmetatype.cpp \ - kernel/qmimedata.cpp \ - kernel/qobject.cpp \ - kernel/qobjectcleanuphandler.cpp \ - kernel/qsignalmapper.cpp \ - kernel/qsocketnotifier.cpp \ - kernel/qtimer.cpp \ - kernel/qtranslator.cpp \ - kernel/qvariant.cpp \ + kernel/qbasictimer.cpp \ + kernel/qeventloop.cpp \ + kernel/qcoreapplication.cpp \ + kernel/qcoreevent.cpp \ + kernel/qmetaobject.cpp \ + kernel/qmetatype.cpp \ + kernel/qmimedata.cpp \ + kernel/qobject.cpp \ + kernel/qobjectcleanuphandler.cpp \ + kernel/qsignalmapper.cpp \ + kernel/qsocketnotifier.cpp \ + kernel/qtimer.cpp \ + kernel/qtranslator.cpp \ + kernel/qvariant.cpp \ kernel/qcoreglobaldata.cpp \ kernel/qsharedmemory.cpp \ kernel/qsystemsemaphore.cpp \ kernel/qpointer.cpp \ - kernel/qmath.cpp + kernel/qmath.cpp \ + kernel/qsystemerror.cpp win32 { - SOURCES += \ - kernel/qeventdispatcher_win.cpp \ - kernel/qcoreapplication_win.cpp \ - kernel/qwineventnotifier_p.cpp \ + SOURCES += \ + kernel/qeventdispatcher_win.cpp \ + kernel/qcoreapplication_win.cpp \ + kernel/qwineventnotifier_p.cpp \ kernel/qsharedmemory_win.cpp \ kernel/qsystemsemaphore_win.cpp - HEADERS += \ - kernel/qeventdispatcher_win_p.h \ - kernel/qwineventnotifier_p.h + HEADERS += \ + kernel/qeventdispatcher_win_p.h \ + kernel/qwineventnotifier_p.h } wince*: { - SOURCES += \ - kernel/qfunctions_wince.cpp - HEADERS += \ - kernel/qfunctions_wince.h + SOURCES += \ + kernel/qfunctions_wince.cpp + HEADERS += \ + kernel/qfunctions_wince.h } mac:!embedded:!qpa{ @@ -85,18 +87,18 @@ mac:!embedded:!qpa{ mac:!nacl { SOURCES += \ - kernel/qcore_mac.cpp + kernel/qcore_mac.cpp } unix:!symbian { - SOURCES += \ + SOURCES += \ kernel/qcore_unix.cpp \ kernel/qcrashhandler.cpp \ kernel/qsharedmemory_unix.cpp \ kernel/qsystemsemaphore_unix.cpp - HEADERS += \ + HEADERS += \ kernel/qcore_unix_p.h \ - kernel/qcrashhandler_p.h + kernel/qcrashhandler_p.h contains(QT_CONFIG, glib) { SOURCES += \ @@ -115,7 +117,7 @@ unix:!symbian { } symbian { - SOURCES += \ + SOURCES += \ kernel/qcore_unix.cpp \ kernel/qcrashhandler.cpp \ kernel/qeventdispatcher_symbian.cpp \ @@ -123,7 +125,7 @@ symbian { kernel/qsharedmemory_symbian.cpp \ kernel/qsystemsemaphore_symbian.cpp - HEADERS += \ + HEADERS += \ kernel/qcore_unix_p.h \ kernel/qcrashhandler_p.h \ kernel/qeventdispatcher_symbian_p.h \ @@ -131,9 +133,9 @@ symbian { } vxworks { - SOURCES += \ - kernel/qfunctions_vxworks.cpp - HEADERS += \ - kernel/qfunctions_vxworks.h + SOURCES += \ + kernel/qfunctions_vxworks.cpp + HEADERS += \ + kernel/qfunctions_vxworks.h } diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index a8dc491..0f95ee0 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -71,6 +71,7 @@ # include <e32ldr.h> # include "qeventdispatcher_symbian_p.h" # include "private/qcore_symbian_p.h" +# include "private/qfilesystemengine_p.h" #elif defined(Q_OS_UNIX) # if !defined(QT_NO_GLIB) # include "qeventdispatcher_glib_p.h" @@ -567,6 +568,12 @@ void QCoreApplication::init() Q_ASSERT_X(!self, "QCoreApplication", "there should be only one application object"); QCoreApplication::self = this; +#ifdef Q_OS_SYMBIAN + //ensure temp and working directories exist + QFileSystemEngine::createDirectory(QFileSystemEntry(QFileSystemEngine::tempPath()), true); + QFileSystemEngine::createDirectory(QFileSystemEntry(QFileSystemEngine::currentPath()), true); +#endif + #ifndef QT_NO_THREAD QThread::initialize(); #endif diff --git a/src/corelib/kernel/qsystemerror.cpp b/src/corelib/kernel/qsystemerror.cpp new file mode 100644 index 0000000..953ed95 --- /dev/null +++ b/src/corelib/kernel/qsystemerror.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> +#include "qsystemerror_p.h" +#if !defined(Q_OS_WINCE) +# include <errno.h> +# if defined(Q_CC_MSVC) +# include <crtdbg.h> +# endif +#endif +#ifdef Q_OS_WIN +#include <windows.h> +#endif + +QT_BEGIN_NAMESPACE + +#if !defined(Q_OS_WIN) && !defined(QT_NO_THREAD) && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX) && \ + defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L +namespace { + // There are two incompatible versions of strerror_r: + // a) the XSI/POSIX.1 version, which returns an int, + // indicating success or not + // b) the GNU version, which returns a char*, which may or may not + // be the beginning of the buffer we used + // The GNU libc manpage for strerror_r says you should use the the XSI + // version in portable code. However, it's impossible to do that if + // _GNU_SOURCE is defined so we use C++ overloading to decide what to do + // depending on the return type + static inline QString fromstrerror_helper(int, const QByteArray &buf) + { + return QString::fromLocal8Bit(buf); + } + static inline QString fromstrerror_helper(const char *str, const QByteArray &) + { + return QString::fromLocal8Bit(str); + } +} +#endif + +static QString standardLibraryErrorString(int errorCode) +{ + const char *s = 0; + QString ret; + switch (errorCode) { + case 0: + break; + case EACCES: + s = QT_TRANSLATE_NOOP("QIODevice", "Permission denied"); + break; + case EMFILE: + s = QT_TRANSLATE_NOOP("QIODevice", "Too many open files"); + break; + case ENOENT: + s = QT_TRANSLATE_NOOP("QIODevice", "No such file or directory"); + break; + case ENOSPC: + s = QT_TRANSLATE_NOOP("QIODevice", "No space left on device"); + break; + default: { + #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX) + QByteArray buf(1024, '\0'); + ret = fromstrerror_helper(strerror_r(errorCode, buf.data(), buf.size()), buf); + #else + ret = QString::fromLocal8Bit(strerror(errorCode)); + #endif + break; } + } + if (s) { + // ######## this breaks moc build currently + // ret = QCoreApplication::translate("QIODevice", s); + ret = QString::fromLatin1(s); + } + return ret.trimmed(); +} + +#ifdef Q_OS_WIN +static QString windowsErrorString(int errorCode) +{ + QString ret; + wchar_t *string = 0; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&string, + 0, + NULL); + ret = QString::fromWCharArray(string); + LocalFree((HLOCAL)string); + + if (ret.isEmpty() && errorCode == ERROR_MOD_NOT_FOUND) + ret = QString::fromLatin1("The specified module could not be found."); + return ret; +} +#endif + +#ifdef Q_OS_SYMBIAN +static QString symbianErrorString(int errorCode) +{ + switch (errorCode) { + case KErrNotFound: + return QLatin1String("not found"); + case KErrCancel: + return QLatin1String("cancelled"); + case KErrNoMemory: + return QLatin1String("out of memory"); + case KErrNotSupported: + return QLatin1String("not supported"); + case KErrBadHandle: + return QLatin1String("bad handle"); //KERN-EXEC 0 panic is more likely + case KErrAlreadyExists: + return QLatin1String("already exists"); + case KErrPathNotFound: + return QLatin1String("path not found"); + case KErrInUse: + return QLatin1String("in use"); + case KErrNotReady: + return QLatin1String("not ready (e.g. FS dismounted, no memory card)"); + case KErrCorrupt: + return QLatin1String("corrupt"); + case KErrAccessDenied: + return QLatin1String("access denied"); + case KErrLocked: + return QLatin1String("locked"); + case KErrWrite: + return QLatin1String("incomplete write error"); + case KErrDisMounted: + return QLatin1String("file system dismounted during operation"); //i.e. a forcible dismount was done while we had files open + case KErrEof: + return QLatin1String("end of file"); + case KErrDiskFull: + return QLatin1String("no space in file system"); + case KErrBadName: + return QLatin1String("invalid filename"); + case KErrTimedOut: + return QLatin1String("timed out"); + case KErrBadDescriptor: + return QLatin1String("bad descriptor (passed address on stack to async call?)"); + case KErrAbort: + return QLatin1String("aborted"); + case KErrTooBig: + return QLatin1String("too big"); //e.g. trying to open a >2GB file with 32 bit API + case KErrBadPower: + return QLatin1String("insufficient power"); + case KErrDirFull: + return QLatin1String("no space in directory table"); + case KErrHardwareNotAvailable: + return QLatin1String("hardware not available"); + case KErrSessionClosed: + return QLatin1String("session closed"); + case KErrPermissionDenied: + return QLatin1String("permission denied"); + default: + return QString(QLatin1String("symbian error %d")).arg(errorCode); + } +} +#endif + +QString QSystemError::toString() +{ + switch(errorScope) { + case NativeError: +#if defined (Q_OS_WIN) + return windowsErrorString(errorCode); +#elif defined (Q_OS_SYMBIAN) + return symbianErrorString(errorCode); +#else + //unix: fall through as native and standard library are the same +#endif + case StandardLibraryError: + return standardLibraryErrorString(errorCode); + default: + qWarning("invalid error scope"); + //fall through + case NoError: + return QLatin1String("No error"); + } +} + +QT_END_NAMESPACE + diff --git a/src/corelib/kernel/qsystemerror_p.h b/src/corelib/kernel/qsystemerror_p.h new file mode 100644 index 0000000..c2a13a8 --- /dev/null +++ b/src/corelib/kernel/qsystemerror_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSYSTEMERROR_P_H +#define QSYSTEMERROR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qstring.h> + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QSystemError +{ +public: + enum ErrorScope + { + NoError, + StandardLibraryError, + NativeError + }; + + inline QSystemError(int error, ErrorScope scope); + inline QSystemError(); + + QString toString(); + inline ErrorScope scope(); + inline int error(); + + //data members + int errorCode; + ErrorScope errorScope; +}; + +QSystemError::QSystemError(int error, QSystemError::ErrorScope scope) +: errorCode(error), errorScope(scope) +{ + +} + +QSystemError::QSystemError() +: errorCode(0), errorScope(NoError) +{ + +} + +QSystemError::ErrorScope QSystemError::scope() +{ + return errorScope; +} + +int QSystemError::error() +{ + return errorCode; +} + + +QT_END_NAMESPACE + +#endif // QSYSTEMERROR_P_H diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index c252e64..6a20c7a 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -5838,6 +5838,41 @@ bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::S return (s1.type == s2.type) && (s1.pos == s2.pos) && (s1.count == s2.count); } +#ifdef Q_OS_SYMBIAN +const static TTime UnixEpochOffset(I64LIT(0xdcddb30f2f8000)); +const static TInt64 MinimumMillisecondTime(KMinTInt64 / 1000); +const static TInt64 MaximumMillisecondTime(KMaxTInt64 / 1000); +QDateTime qt_symbian_TTime_To_QDateTime(const TTime& time) +{ + TTimeIntervalMicroSeconds absolute = time.MicroSecondsFrom(UnixEpochOffset); + + return QDateTime::fromMSecsSinceEpoch(absolute.Int64() / 1000); +} + +TTime qt_symbian_QDateTime_To_TTime(const QDateTime& datetime) +{ + qint64 absolute = datetime.toMSecsSinceEpoch(); + if(absolute > MaximumMillisecondTime) + return TTime(KMaxTInt64); + if(absolute < MinimumMillisecondTime) + return TTime(KMinTInt64); + return TTime(absolute * 1000); +} + +time_t qt_symbian_TTime_To_time_t(const TTime& time) +{ + TTimeIntervalSeconds interval; + TInt err = time.SecondsFrom(UnixEpochOffset, interval); + if (err || interval.Int() < 0) + return (time_t) 0; + return (time_t) interval.Int(); +} + +TTime qt_symbian_time_t_To_TTime(time_t time) +{ + return UnixEpochOffset + TTimeIntervalSeconds(time); +} +#endif //Q_OS_SYMBIAN #endif // QT_BOOTSTRAPPED diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h index f10785e..8355ef7 100644 --- a/src/corelib/tools/qdatetime_p.h +++ b/src/corelib/tools/qdatetime_p.h @@ -275,6 +275,12 @@ Q_CORE_EXPORT bool operator==(const QDateTimeParser::SectionNode &s1, const QDat Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::Sections) Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::FieldInfo) +#ifdef Q_OS_SYMBIAN +QDateTime qt_symbian_TTime_To_QDateTime(const TTime& time); +TTime qt_symbian_QDateTime_To_TTime(const QDateTime& datetime); +time_t qt_symbian_TTime_To_time_t(const TTime& time); +TTime qt_symbian_time_t_To_TTime(time_t time); +#endif //Q_OS_SYMBIAN #endif // QT_BOOTSTRAPPED diff --git a/src/declarative/qml/qdeclarativeglobal_p.h b/src/declarative/qml/qdeclarativeglobal_p.h index 31fbb1e..b8428b8 100644 --- a/src/declarative/qml/qdeclarativeglobal_p.h +++ b/src/declarative/qml/qdeclarativeglobal_p.h @@ -65,7 +65,7 @@ QT_MODULE(Declarative) } #ifdef Q_OS_SYMBIAN -#define Q_DECLARATIVE_PRIVATE_EXPORT +#define Q_DECLARATIVE_PRIVATE_EXPORT Q_AUTOTEST_EXPORT #else #define Q_DECLARATIVE_PRIVATE_EXPORT Q_DECLARATIVE_EXPORT #endif diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index 5002beb..6552370 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -1313,7 +1313,7 @@ QString QFileSystemModelPrivate::filePath(const QModelIndex &index) const if ((fullPath.length() > 2) && fullPath[0] == QLatin1Char('/') && fullPath[1] == QLatin1Char('/')) fullPath = fullPath.mid(1); #endif -#if defined(Q_OS_WIN) +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) if (fullPath.length() == 2 && fullPath.endsWith(QLatin1Char(':'))) fullPath.append(QLatin1Char('/')); #endif diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index f352871..5f01bcb 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1614,6 +1614,9 @@ extern void qt_cleanup_symbianFontDatabaseExtras(); // qfontdatabase_s60.cpp *****************************************************************************/ void qt_cleanup() { +#ifdef Q_WS_S60 + S60->setButtonGroupContainer(0); +#endif if(qt_S60Beep) { delete qt_S60Beep; qt_S60Beep = 0; diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def index b678b4e..84aa246 100644 --- a/src/s60installs/bwins/QtCoreu.def +++ b/src/s60installs/bwins/QtCoreu.def @@ -4585,4 +4585,9 @@ EXPORTS ?advance@QAnimationDriver@@QAEXXZ @ 4584 NONAME ; void QAnimationDriver::advance(void) ?start@QAnimationDriver@@AAEXXZ @ 4585 NONAME ; void QAnimationDriver::start(void) ?unlockInline@QMutex@@QAEXXZ @ 4586 NONAME ; void QMutex::unlockInline(void) - + ??0QSystemError@@QAE@HW4ErrorScope@0@@Z @ 4587 NONAME ; QSystemError::QSystemError(int, enum QSystemError::ErrorScope) + ??0QSystemError@@QAE@XZ @ 4588 NONAME ; QSystemError::QSystemError(void) + ?error@QSystemError@@QAEHXZ @ 4589 NONAME ; int QSystemError::error(void) + ?scope@QSystemError@@QAE?AW4ErrorScope@1@XZ @ 4590 NONAME ; enum QSystemError::ErrorScope QSystemError::scope(void) + ?toString@QSystemError@@QAE?AVQString@@XZ @ 4591 NONAME ; class QString QSystemError::toString(void) + ??0QFileInfo@@QAE@PAVQFileInfoPrivate@@@Z @ 4592 NONAME ; QFileInfo::QFileInfo(class QFileInfoPrivate *) diff --git a/src/s60installs/eabi/QtCoreu.def b/src/s60installs/eabi/QtCoreu.def index 02e72a1..130d9c0 100644 --- a/src/s60installs/eabi/QtCoreu.def +++ b/src/s60installs/eabi/QtCoreu.def @@ -3791,4 +3791,8 @@ EXPORTS _ZTV13QUnifiedTimer @ 3790 NONAME _ZTV16QAnimationDriver @ 3791 NONAME _ZTV23QAnimationDriverPrivate @ 3792 NONAME + _ZN12QSystemError8toStringEv @ 3793 NONAME + _ZN5QChar21currentUnicodeVersionEv @ 3794 NONAME + _ZN9QFileInfoC1EP16QFileInfoPrivate @ 3795 NONAME + _ZN9QFileInfoC2EP16QFileInfoPrivate @ 3796 NONAME diff --git a/src/s60installs/eabi/QtDeclarativeu.def b/src/s60installs/eabi/QtDeclarativeu.def index 396c133..b0efab4 100644 --- a/src/s60installs/eabi/QtDeclarativeu.def +++ b/src/s60installs/eabi/QtDeclarativeu.def @@ -1747,8 +1747,8 @@ EXPORTS _ZN21QDeclarativeListModelC1EPKS_P32QDeclarativeListModelWorkerAgent @ 1746 NONAME ABSENT _ZN21QDeclarativeListModelC2EPKS_P32QDeclarativeListModelWorkerAgent @ 1747 NONAME ABSENT _ZNK21QDeclarativeListModel14inWorkerThreadEv @ 1748 NONAME ABSENT - _ZN23QDeclarativeDebugHelper15getScriptEngineEP18QDeclarativeEngine @ 1749 NONAME ABSENT - _ZN23QDeclarativeDebugHelper26setAnimationSlowDownFactorEf @ 1750 NONAME ABSENT + _ZN23QDeclarativeDebugHelper15getScriptEngineEP18QDeclarativeEngine @ 1749 NONAME + _ZN23QDeclarativeDebugHelper26setAnimationSlowDownFactorEf @ 1750 NONAME _ZN17QDeclarativeTimer10classBeginEv @ 1751 NONAME ABSENT _ZN17QDeclarativeTimer10setRunningEb @ 1752 NONAME ABSENT _ZN17QDeclarativeTimer11qt_metacallEN11QMetaObject4CallEiPPv @ 1753 NONAME ABSENT @@ -1883,6 +1883,6 @@ EXPORTS _ZThn8_N29QDeclarativeAbstractAnimation9setTargetERK20QDeclarativeProperty @ 1882 NONAME ABSENT _ZThn8_N29QDeclarativeAbstractAnimationD0Ev @ 1883 NONAME ABSENT _ZThn8_N29QDeclarativeAbstractAnimationD1Ev @ 1884 NONAME ABSENT - _ZN23QDeclarativeDebugHelper15enableDebuggingEv @ 1885 NONAME ABSENT + _ZN23QDeclarativeDebugHelper15enableDebuggingEv @ 1885 NONAME _ZN27QDeclarativePropertyPrivate7connectEPK7QObjectiS2_iiPi @ 1886 NONAME ABSENT diff --git a/src/s60installs/eabi/QtGuiu.def b/src/s60installs/eabi/QtGuiu.def index 703d11b..926ed52 100644 --- a/src/s60installs/eabi/QtGuiu.def +++ b/src/s60installs/eabi/QtGuiu.def @@ -12105,7 +12105,7 @@ EXPORTS _ZN15QStaticTextItemD1Ev @ 12104 NONAME _ZN15QStaticTextItemD2Ev @ 12105 NONAME _ZN19QEventDispatcherS6031reactivateDeferredActiveObjectsEv @ 12106 NONAME - _Z18qt_addBitmapToPathffPKhiiiP12QPainterPath @ 12107 NONAME ABSENT + _Z18qt_addBitmapToPathffPKhiiiP12QPainterPath @ 12107 NONAME _Z22qt_fontdata_from_indexi @ 12108 NONAME _ZN10QBlittable4lockEv @ 12109 NONAME _ZN10QBlittable6unlockEv @ 12110 NONAME diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro index 27b7336..9e5845c 100644 --- a/src/tools/bootstrap/bootstrap.pro +++ b/src/tools/bootstrap/bootstrap.pro @@ -59,6 +59,8 @@ SOURCES += \ ../../corelib/io/qdiriterator.cpp \ ../../corelib/io/qfile.cpp \ ../../corelib/io/qfileinfo.cpp \ + ../../corelib/io/qfilesystementry.cpp \ + ../../corelib/io/qfilesystemengine.cpp \ ../../corelib/io/qfsfileengine.cpp \ ../../corelib/io/qfsfileengine_iterator.cpp \ ../../corelib/io/qiodevice.cpp \ @@ -67,6 +69,7 @@ SOURCES += \ ../../corelib/io/qurl.cpp \ ../../corelib/kernel/qmetatype.cpp \ ../../corelib/kernel/qvariant.cpp \ + ../../corelib/kernel/qsystemerror.cpp \ ../../corelib/tools/qbitarray.cpp \ ../../corelib/tools/qbytearray.cpp \ ../../corelib/tools/qbytearraymatcher.cpp \ @@ -81,19 +84,22 @@ SOURCES += \ ../../corelib/tools/qvector.cpp \ ../../corelib/tools/qvsnprintf.cpp \ ../../corelib/xml/qxmlutils.cpp \ - ../../corelib/xml/qxmlstream.cpp \ + ../../corelib/xml/qxmlstream.cpp \ ../../xml/dom/qdom.cpp \ ../../xml/sax/qxml.cpp -unix:SOURCES += ../../corelib/io/qfsfileengine_unix.cpp \ - ../../corelib/io/qfsfileengine_iterator_unix.cpp +unix:SOURCES += ../../corelib/io/qfilesystemengine_unix.cpp \ + ../../corelib/io/qfilesystemiterator_unix.cpp \ + ../../corelib/io/qfsfileengine_unix.cpp -win32:SOURCES += ../../corelib/io/qfsfileengine_win.cpp \ - ../../corelib/io/qfsfileengine_iterator_win.cpp \ +win32:SOURCES += ../../corelib/io/qfilesystemengine_win.cpp \ + ../../corelib/io/qfilesystemiterator_win.cpp \ + ../../corelib/io/qfsfileengine_win.cpp \ ../../corelib/plugin/qsystemlibrary.cpp \ macx: { QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 #enables weak linking for 10.4 (exported) + SOURCES += ../../corelib/io/qfilesystemengine_mac.cpp SOURCES += ../../corelib/kernel/qcore_mac.cpp LIBS += -framework CoreServices } diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index b203473..0000000 --- a/tests/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -QObject.log -tst_* -!tst_*.* -tst_*.log -tst_*.debug -tst_*~ diff --git a/tests/auto/collections/tst_collections.cpp b/tests/auto/collections/tst_collections.cpp index cf9fa53..225fe79 100644 --- a/tests/auto/collections/tst_collections.cpp +++ b/tests/auto/collections/tst_collections.cpp @@ -3635,7 +3635,7 @@ template<template<class, class> class C> void QTBUG13079_collectionInsideCollect } -static quint32 qHash(const QTBUG13079_Node<QSet> &) +quint32 qHash(const QTBUG13079_Node<QSet> &) { return 0; } diff --git a/tests/auto/corelib.pro b/tests/auto/corelib.pro index d1d0940..3451b53 100644 --- a/tests/auto/corelib.pro +++ b/tests/auto/corelib.pro @@ -101,6 +101,8 @@ SUBDIRS=\ qwritelocker \ selftests \ utf8 \ + qfilesystementry \ + qabstractfileengine symbian:SUBDIRS -= \ qtconcurrentfilter \ diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index f0fcfa9..499c155 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -8,74 +8,78 @@ SUBDIRS += \ SUBDIRS += \ examples \ parserstress \ + qdeclarativecomponent \ + qdeclarativecontext \ + qdeclarativeengine \ + qdeclarativeerror \ + qdeclarativefolderlistmodel \ + qdeclarativeinfo \ + qdeclarativelayoutitem \ + qdeclarativelistreference \ + qdeclarativemoduleplugin \ + qdeclarativeparticles \ + qdeclarativepixmapcache \ + qdeclarativeqt \ + qdeclarativeview \ + qdeclarativeviewer \ + qdeclarativexmlhttprequest \ + qmlvisual \ + moduleqt47 + +contains(QT_CONFIG, private_tests) { + SUBDIRS += \ qdeclarativeanchors \ qdeclarativeanimatedimage \ qdeclarativeanimations \ qdeclarativebehaviors \ qdeclarativebinding \ qdeclarativeborderimage \ - qdeclarativecomponent \ qdeclarativeconnection \ - qdeclarativecontext \ qdeclarativedebug \ qdeclarativedebugclient \ qdeclarativedebugservice \ qdeclarativedom \ qdeclarativeecmascript \ - qdeclarativeengine \ - qdeclarativeerror \ - qdeclarativefolderlistmodel \ - qdeclarativefontloader \ qdeclarativeflickable \ qdeclarativeflipable \ qdeclarativefocusscope \ + qdeclarativefontloader \ qdeclarativegridview \ qdeclarativeimage \ qdeclarativeimageprovider \ - qdeclarativeinfo \ qdeclarativeinstruction \ qdeclarativeitem \ qdeclarativelanguage \ - qdeclarativelayoutitem \ qdeclarativelistmodel \ - qdeclarativelistreference \ qdeclarativelistview \ qdeclarativeloader \ - qdeclarativemoduleplugin \ qdeclarativemousearea \ - qdeclarativeparticles \ qdeclarativepathview \ - qdeclarativepixmapcache \ qdeclarativepositioners \ qdeclarativeproperty \ qdeclarativepropertymap \ - qdeclarativeqt \ qdeclarativerepeater \ qdeclarativesmoothedanimation \ qdeclarativespringanimation \ + qdeclarativestyledtext \ qdeclarativesqldatabase \ qdeclarativestates \ - qdeclarativestyledtext \ qdeclarativesystempalette \ qdeclarativetext \ qdeclarativetextedit \ qdeclarativetextinput \ qdeclarativetimer \ qdeclarativevaluetypes \ - qdeclarativeview \ - qdeclarativeviewer \ qdeclarativevisualdatamodel \ qdeclarativeworkerscript \ - qdeclarativexmlhttprequest \ qdeclarativexmllistmodel \ - qmlvisual \ - qpacketprotocol \ - moduleqt47 + qpacketprotocol contains(QT_CONFIG, webkit) { SUBDIRS += \ qdeclarativewebview } +} # Tests which should run in Pulse PULSE_TESTS = $$SUBDIRS diff --git a/tests/auto/declarative/examples/examples.pro b/tests/auto/declarative/examples/examples.pro index 8ed33da..dafc146 100644 --- a/tests/auto/declarative/examples/examples.pro +++ b/tests/auto/declarative/examples/examples.pro @@ -6,10 +6,12 @@ SOURCES += tst_examples.cpp include(../../../../tools/qml/qml.pri) +include(../symbianlibs.pri) + symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/moduleqt47/moduleqt47.pro b/tests/auto/declarative/moduleqt47/moduleqt47.pro index 808f263..ff773e8 100644 --- a/tests/auto/declarative/moduleqt47/moduleqt47.pro +++ b/tests/auto/declarative/moduleqt47/moduleqt47.pro @@ -7,7 +7,7 @@ SOURCES += tst_moduleqt47.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/parserstress/parserstress.pro b/tests/auto/declarative/parserstress/parserstress.pro index 1e323f7..6ef2432 100644 --- a/tests/auto/declarative/parserstress/parserstress.pro +++ b/tests/auto/declarative/parserstress/parserstress.pro @@ -7,7 +7,7 @@ SOURCES += tst_parserstress.cpp symbian: { importFiles.files = ..\\..\\qscriptjstestsuite\\tests importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeanchors/qdeclarativeanchors.pro b/tests/auto/declarative/qdeclarativeanchors/qdeclarativeanchors.pro index 141e25d..f09e8d9 100644 --- a/tests/auto/declarative/qdeclarativeanchors/qdeclarativeanchors.pro +++ b/tests/auto/declarative/qdeclarativeanchors/qdeclarativeanchors.pro @@ -6,7 +6,7 @@ macx:CONFIG -= app_bundle symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeanimatedimage/qdeclarativeanimatedimage.pro b/tests/auto/declarative/qdeclarativeanimatedimage/qdeclarativeanimatedimage.pro index ad9509a..3d040a6 100644 --- a/tests/auto/declarative/qdeclarativeanimatedimage/qdeclarativeanimatedimage.pro +++ b/tests/auto/declarative/qdeclarativeanimatedimage/qdeclarativeanimatedimage.pro @@ -7,7 +7,7 @@ macx:CONFIG -= app_bundle symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeanimations/qdeclarativeanimations.pro b/tests/auto/declarative/qdeclarativeanimations/qdeclarativeanimations.pro index 84cd498..d00d51a 100644 --- a/tests/auto/declarative/qdeclarativeanimations/qdeclarativeanimations.pro +++ b/tests/auto/declarative/qdeclarativeanimations/qdeclarativeanimations.pro @@ -6,7 +6,7 @@ macx:CONFIG -= app_bundle symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativebehaviors/qdeclarativebehaviors.pro b/tests/auto/declarative/qdeclarativebehaviors/qdeclarativebehaviors.pro index e4125fd..7416827 100644 --- a/tests/auto/declarative/qdeclarativebehaviors/qdeclarativebehaviors.pro +++ b/tests/auto/declarative/qdeclarativebehaviors/qdeclarativebehaviors.pro @@ -6,7 +6,7 @@ macx:CONFIG -= app_bundle symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativebinding/qdeclarativebinding.pro b/tests/auto/declarative/qdeclarativebinding/qdeclarativebinding.pro index 25bdbec..fe12635 100644 --- a/tests/auto/declarative/qdeclarativebinding/qdeclarativebinding.pro +++ b/tests/auto/declarative/qdeclarativebinding/qdeclarativebinding.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativebinding.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeborderimage/qdeclarativeborderimage.pro b/tests/auto/declarative/qdeclarativeborderimage/qdeclarativeborderimage.pro index 05d4cac..a7463e8 100644 --- a/tests/auto/declarative/qdeclarativeborderimage/qdeclarativeborderimage.pro +++ b/tests/auto/declarative/qdeclarativeborderimage/qdeclarativeborderimage.pro @@ -8,7 +8,7 @@ SOURCES += tst_qdeclarativeborderimage.cpp ../shared/testhttpserver.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro b/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro index c614571..6f9550d 100644 --- a/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro +++ b/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativeconnection.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativedom/qdeclarativedom.pro b/tests/auto/declarative/qdeclarativedom/qdeclarativedom.pro index e8f24a5..8ac69aa 100644 --- a/tests/auto/declarative/qdeclarativedom/qdeclarativedom.pro +++ b/tests/auto/declarative/qdeclarativedom/qdeclarativedom.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativedom.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro b/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro index e7f8636..69d25a4 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro +++ b/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro @@ -15,7 +15,7 @@ INCLUDEPATH += ../shared symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeflickable/qdeclarativeflickable.pro b/tests/auto/declarative/qdeclarativeflickable/qdeclarativeflickable.pro index 1fb99d0..c176e07 100644 --- a/tests/auto/declarative/qdeclarativeflickable/qdeclarativeflickable.pro +++ b/tests/auto/declarative/qdeclarativeflickable/qdeclarativeflickable.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativeflickable.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeflipable/qdeclarativeflipable.pro b/tests/auto/declarative/qdeclarativeflipable/qdeclarativeflipable.pro index eddd053..3b6d19a 100644 --- a/tests/auto/declarative/qdeclarativeflipable/qdeclarativeflipable.pro +++ b/tests/auto/declarative/qdeclarativeflipable/qdeclarativeflipable.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativeflipable.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativefocusscope/qdeclarativefocusscope.pro b/tests/auto/declarative/qdeclarativefocusscope/qdeclarativefocusscope.pro index fd7f6b8..eab983f 100644 --- a/tests/auto/declarative/qdeclarativefocusscope/qdeclarativefocusscope.pro +++ b/tests/auto/declarative/qdeclarativefocusscope/qdeclarativefocusscope.pro @@ -6,7 +6,7 @@ macx:CONFIG -= app_bundle symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativefolderlistmodel/qdeclarativefolderlistmodel.pro b/tests/auto/declarative/qdeclarativefolderlistmodel/qdeclarativefolderlistmodel.pro index 50c7ca0..b7e5e5f 100644 --- a/tests/auto/declarative/qdeclarativefolderlistmodel/qdeclarativefolderlistmodel.pro +++ b/tests/auto/declarative/qdeclarativefolderlistmodel/qdeclarativefolderlistmodel.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativefolderlistmodel.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativefontloader/qdeclarativefontloader.pro b/tests/auto/declarative/qdeclarativefontloader/qdeclarativefontloader.pro index f245a0d..357268b 100644 --- a/tests/auto/declarative/qdeclarativefontloader/qdeclarativefontloader.pro +++ b/tests/auto/declarative/qdeclarativefontloader/qdeclarativefontloader.pro @@ -8,7 +8,7 @@ SOURCES += tst_qdeclarativefontloader.cpp ../shared/testhttpserver.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativegridview/qdeclarativegridview.pro b/tests/auto/declarative/qdeclarativegridview/qdeclarativegridview.pro index b775b3d..bc196fb 100644 --- a/tests/auto/declarative/qdeclarativegridview/qdeclarativegridview.pro +++ b/tests/auto/declarative/qdeclarativegridview/qdeclarativegridview.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativegridview.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeimage/qdeclarativeimage.pro b/tests/auto/declarative/qdeclarativeimage/qdeclarativeimage.pro index c87c1d9..a22c8b5 100644 --- a/tests/auto/declarative/qdeclarativeimage/qdeclarativeimage.pro +++ b/tests/auto/declarative/qdeclarativeimage/qdeclarativeimage.pro @@ -8,7 +8,7 @@ SOURCES += tst_qdeclarativeimage.cpp ../shared/testhttpserver.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeinfo/qdeclarativeinfo.pro b/tests/auto/declarative/qdeclarativeinfo/qdeclarativeinfo.pro index 888596f..423390f 100644 --- a/tests/auto/declarative/qdeclarativeinfo/qdeclarativeinfo.pro +++ b/tests/auto/declarative/qdeclarativeinfo/qdeclarativeinfo.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativeinfo.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeitem/qdeclarativeitem.pro b/tests/auto/declarative/qdeclarativeitem/qdeclarativeitem.pro index 0fd871e..d8007a0 100644 --- a/tests/auto/declarative/qdeclarativeitem/qdeclarativeitem.pro +++ b/tests/auto/declarative/qdeclarativeitem/qdeclarativeitem.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativeitem.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro b/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro index aa69337..cae85a7 100644 --- a/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro +++ b/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro @@ -14,7 +14,7 @@ SOURCES += ../shared/testhttpserver.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativelayoutitem/qdeclarativelayoutitem.pro b/tests/auto/declarative/qdeclarativelayoutitem/qdeclarativelayoutitem.pro index 42d9a80..d89f16c 100644 --- a/tests/auto/declarative/qdeclarativelayoutitem/qdeclarativelayoutitem.pro +++ b/tests/auto/declarative/qdeclarativelayoutitem/qdeclarativelayoutitem.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativelayoutitem.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro index 8a39555..b5c5cf2 100644 --- a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro +++ b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro @@ -8,7 +8,7 @@ SOURCES += tst_qdeclarativelistmodel.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativelistview/qdeclarativelistview.pro b/tests/auto/declarative/qdeclarativelistview/qdeclarativelistview.pro index 99eba67..468474a 100644 --- a/tests/auto/declarative/qdeclarativelistview/qdeclarativelistview.pro +++ b/tests/auto/declarative/qdeclarativelistview/qdeclarativelistview.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativelistview.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeloader/qdeclarativeloader.pro b/tests/auto/declarative/qdeclarativeloader/qdeclarativeloader.pro index 1e7808a..1ede509 100644 --- a/tests/auto/declarative/qdeclarativeloader/qdeclarativeloader.pro +++ b/tests/auto/declarative/qdeclarativeloader/qdeclarativeloader.pro @@ -10,7 +10,7 @@ SOURCES += tst_qdeclarativeloader.cpp \ symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.pro b/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.pro index ec2d25e..2e8aa75 100644 --- a/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.pro +++ b/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.pro @@ -6,7 +6,7 @@ CONFIG -= app_bundle symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativemousearea/qdeclarativemousearea.pro b/tests/auto/declarative/qdeclarativemousearea/qdeclarativemousearea.pro index a93f7af..ed9313f 100644 --- a/tests/auto/declarative/qdeclarativemousearea/qdeclarativemousearea.pro +++ b/tests/auto/declarative/qdeclarativemousearea/qdeclarativemousearea.pro @@ -8,7 +8,7 @@ SOURCES += tst_qdeclarativemousearea.cpp ../shared/testhttpserver.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeparticles/qdeclarativeparticles.pro b/tests/auto/declarative/qdeclarativeparticles/qdeclarativeparticles.pro index 8f13573..2cf8268 100644 --- a/tests/auto/declarative/qdeclarativeparticles/qdeclarativeparticles.pro +++ b/tests/auto/declarative/qdeclarativeparticles/qdeclarativeparticles.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativeparticles.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativepathview/qdeclarativepathview.pro b/tests/auto/declarative/qdeclarativepathview/qdeclarativepathview.pro index 4f70a6f..e0404c5 100644 --- a/tests/auto/declarative/qdeclarativepathview/qdeclarativepathview.pro +++ b/tests/auto/declarative/qdeclarativepathview/qdeclarativepathview.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativepathview.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativepixmapcache/qdeclarativepixmapcache.pro b/tests/auto/declarative/qdeclarativepixmapcache/qdeclarativepixmapcache.pro index 47b1b7b..88871e9 100644 --- a/tests/auto/declarative/qdeclarativepixmapcache/qdeclarativepixmapcache.pro +++ b/tests/auto/declarative/qdeclarativepixmapcache/qdeclarativepixmapcache.pro @@ -12,7 +12,7 @@ SOURCES += ../shared/testhttpserver.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp b/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp index 50d0731..1a38e87 100644 --- a/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp +++ b/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp @@ -74,7 +74,9 @@ private slots: void massive(); void cancelcrash(); void shrinkcache(); +#ifndef QT_NO_CONCURRENT void networkCrash(); +#endif private: QDeclarativeEngine engine; QUrl thisfile; @@ -363,6 +365,7 @@ void createNetworkServer() eventLoop.exec(); } +#ifndef QT_NO_CONCURRENT // QT-3957 void tst_qdeclarativepixmapcache::networkCrash() { @@ -377,6 +380,7 @@ void tst_qdeclarativepixmapcache::networkCrash() } future.cancel(); } +#endif QTEST_MAIN(tst_qdeclarativepixmapcache) diff --git a/tests/auto/declarative/qdeclarativepositioners/qdeclarativepositioners.pro b/tests/auto/declarative/qdeclarativepositioners/qdeclarativepositioners.pro index e98aa5c..27e5948 100644 --- a/tests/auto/declarative/qdeclarativepositioners/qdeclarativepositioners.pro +++ b/tests/auto/declarative/qdeclarativepositioners/qdeclarativepositioners.pro @@ -6,7 +6,7 @@ macx:CONFIG -= app_bundle symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro b/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro index 9dd727c..1750860 100644 --- a/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro +++ b/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativeproperty.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro b/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro index a12c439..71ff8a8 100644 --- a/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro +++ b/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro @@ -6,7 +6,7 @@ macx:CONFIG -= app_bundle symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativerepeater/qdeclarativerepeater.pro b/tests/auto/declarative/qdeclarativerepeater/qdeclarativerepeater.pro index 385b8da..5230f69 100644 --- a/tests/auto/declarative/qdeclarativerepeater/qdeclarativerepeater.pro +++ b/tests/auto/declarative/qdeclarativerepeater/qdeclarativerepeater.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativerepeater.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro b/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro index dedb263..171f308 100644 --- a/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro +++ b/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro @@ -11,7 +11,7 @@ INCLUDEPATH += ../shared symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro b/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro index 69f331b..1e77d6e 100644 --- a/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro +++ b/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativesmoothedanimation.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro b/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro index a59522b..da477fc 100644 --- a/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro +++ b/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativespringanimation.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro b/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro index d938692..0d335a5 100644 --- a/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro +++ b/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro @@ -8,7 +8,7 @@ SOURCES += tst_qdeclarativesqldatabase.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro b/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro index 2f32178..4a0cc24 100644 --- a/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro +++ b/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativestates.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativetext/qdeclarativetext.pro b/tests/auto/declarative/qdeclarativetext/qdeclarativetext.pro index 362886e..290cda3 100644 --- a/tests/auto/declarative/qdeclarativetext/qdeclarativetext.pro +++ b/tests/auto/declarative/qdeclarativetext/qdeclarativetext.pro @@ -12,7 +12,7 @@ SOURCES += ../shared/testhttpserver.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativetextedit/qdeclarativetextedit.pro b/tests/auto/declarative/qdeclarativetextedit/qdeclarativetextedit.pro index cf706ba..aaf753e 100644 --- a/tests/auto/declarative/qdeclarativetextedit/qdeclarativetextedit.pro +++ b/tests/auto/declarative/qdeclarativetextedit/qdeclarativetextedit.pro @@ -8,7 +8,7 @@ HEADERS += ../shared/testhttpserver.h symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativetextinput/qdeclarativetextinput.pro b/tests/auto/declarative/qdeclarativetextinput/qdeclarativetextinput.pro index 5c45f57..0fee1c9 100644 --- a/tests/auto/declarative/qdeclarativetextinput/qdeclarativetextinput.pro +++ b/tests/auto/declarative/qdeclarativetextinput/qdeclarativetextinput.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativetextinput.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro b/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro index a208254..59b3526 100644 --- a/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro +++ b/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro @@ -10,7 +10,7 @@ SOURCES += tst_qdeclarativevaluetypes.cpp \ symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeview/qdeclarativeview.pro b/tests/auto/declarative/qdeclarativeview/qdeclarativeview.pro index 4436d54..fc4790d 100644 --- a/tests/auto/declarative/qdeclarativeview/qdeclarativeview.pro +++ b/tests/auto/declarative/qdeclarativeview/qdeclarativeview.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativeview.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeviewer/qdeclarativeviewer.pro b/tests/auto/declarative/qdeclarativeviewer/qdeclarativeviewer.pro index 5ba416e..8d4b410 100644 --- a/tests/auto/declarative/qdeclarativeviewer/qdeclarativeviewer.pro +++ b/tests/auto/declarative/qdeclarativeviewer/qdeclarativeviewer.pro @@ -6,10 +6,12 @@ include(../../../../tools/qml/qml.pri) SOURCES += tst_qdeclarativeviewer.cpp +include(../symbianlibs.pri) + symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro b/tests/auto/declarative/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro index 16154f3..fe3d794 100644 --- a/tests/auto/declarative/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro +++ b/tests/auto/declarative/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativevisualdatamodel.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativewebview/qdeclarativewebview.pro b/tests/auto/declarative/qdeclarativewebview/qdeclarativewebview.pro index cc7fa43..af13d33 100644 --- a/tests/auto/declarative/qdeclarativewebview/qdeclarativewebview.pro +++ b/tests/auto/declarative/qdeclarativewebview/qdeclarativewebview.pro @@ -8,7 +8,7 @@ SOURCES += tst_qdeclarativewebview.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro b/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro index eca8a68..e20c3e6 100644 --- a/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro +++ b/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro @@ -7,7 +7,7 @@ SOURCES += tst_qdeclarativeworkerscript.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativexmlhttprequest/qdeclarativexmlhttprequest.pro b/tests/auto/declarative/qdeclarativexmlhttprequest/qdeclarativexmlhttprequest.pro index fbcc597..8aefb8e 100644 --- a/tests/auto/declarative/qdeclarativexmlhttprequest/qdeclarativexmlhttprequest.pro +++ b/tests/auto/declarative/qdeclarativexmlhttprequest/qdeclarativexmlhttprequest.pro @@ -11,7 +11,7 @@ SOURCES += tst_qdeclarativexmlhttprequest.cpp \ symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro b/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro index 23173f3..c74b8fb 100644 --- a/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro +++ b/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro @@ -11,7 +11,7 @@ SOURCES += tst_qdeclarativexmllistmodel.cpp symbian: { importFiles.files = data importFiles.path = . - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/auto/declarative/qmlvisual/qmlvisual.pro b/tests/auto/declarative/qmlvisual/qmlvisual.pro index a424b8f..84df15c 100644 --- a/tests/auto/declarative/qmlvisual/qmlvisual.pro +++ b/tests/auto/declarative/qmlvisual/qmlvisual.pro @@ -19,7 +19,6 @@ symbian: { qdeclarativepathview \ qdeclarativepositioners \ qdeclarativesmoothedanimation \ - qdeclarativespringfollow \ qdeclarativetext \ qdeclarativetextedit \ qdeclarativetextinput \ @@ -27,7 +26,7 @@ symbian: { repeater \ selftest_noimages \ webview - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += QT_TEST_SOURCE_DIR=\"\\\"$$PWD\\\"\" } diff --git a/tests/auto/declarative/symbianlibs.pri b/tests/auto/declarative/symbianlibs.pri new file mode 100644 index 0000000..4452f67 --- /dev/null +++ b/tests/auto/declarative/symbianlibs.pri @@ -0,0 +1,9 @@ +#additional libs required for orientation sensor +symbian { + !contains(S60_VERSION, 3.1):!contains(S60_VERSION, 3.2) { + LIBS += -lsensrvclient -lsensrvutil + } + contains(QT_CONFIG, s60): { + LIBS += -lavkon -lcone + } +} diff --git a/tests/auto/networkselftest/networkselftest.pro b/tests/auto/networkselftest/networkselftest.pro index b7c70a1..98e981c 100644 --- a/tests/auto/networkselftest/networkselftest.pro +++ b/tests/auto/networkselftest/networkselftest.pro @@ -6,12 +6,12 @@ QT = core network wince*: { addFiles.files = rfc3252.txt addFiles.path = . - DEPLOYMENT = addFiles + DEPLOYMENT += addFiles DEFINES += SRCDIR=\\\"\\\" } else:symbian { addFiles.files = rfc3252.txt addFiles.path = . - DEPLOYMENT = addFiles + DEPLOYMENT += addFiles } else:vxworks*: { DEFINES += SRCDIR=\\\"\\\" } else { diff --git a/tests/auto/qabstractfileengine/qabstractfileengine.pro b/tests/auto/qabstractfileengine/qabstractfileengine.pro new file mode 100644 index 0000000..870473a --- /dev/null +++ b/tests/auto/qabstractfileengine/qabstractfileengine.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT = core + +SOURCES = tst_qabstractfileengine.cpp +RESOURCES += qabstractfileengine.qrc + diff --git a/tests/auto/qabstractfileengine/qabstractfileengine.qrc b/tests/auto/qabstractfileengine/qabstractfileengine.qrc new file mode 100644 index 0000000..5401b08 --- /dev/null +++ b/tests/auto/qabstractfileengine/qabstractfileengine.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/tst_qabstractfileengine/"> + <file>resources/</file> +</qresource> +</RCC> diff --git a/tests/auto/qabstractfileengine/resources/file.txt b/tests/auto/qabstractfileengine/resources/file.txt new file mode 100644 index 0000000..8a03e0e --- /dev/null +++ b/tests/auto/qabstractfileengine/resources/file.txt @@ -0,0 +1 @@ +This is a simple text file. diff --git a/tests/auto/qabstractfileengine/tst_qabstractfileengine.cpp b/tests/auto/qabstractfileengine/tst_qabstractfileengine.cpp new file mode 100644 index 0000000..5952252 --- /dev/null +++ b/tests/auto/qabstractfileengine/tst_qabstractfileengine.cpp @@ -0,0 +1,765 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QAbstractFileEngine> +#include <QtCore/QFSFileEngine> + +#include <QtCore/QMutex> +#include <QtCore/QMutexLocker> +#include <QtCore/QSharedPointer> +#include <QtCore/QScopedPointer> +#include <QtCore/QHash> + +#include <QtTest/QTest> + +#include <QtCore/QDebug> + +class tst_QAbstractFileEngine + : public QObject +{ + Q_OBJECT +public slots: + void cleanupTestCase(); + +private slots: + void customHandler(); + + void fileIO_data(); + void fileIO(); + +private: + QStringList filesForRemoval; +}; + +class ReferenceFileEngine + : public QAbstractFileEngine +{ +public: + ReferenceFileEngine(const QString &fileName) + : fileName_(fileName) + , position_(-1) + , openForRead_(false) + , openForWrite_(false) + { + } + + bool open(QIODevice::OpenMode openMode) + { + Q_ASSERT(!openForRead_); + Q_ASSERT(!openForWrite_); + + openFile_ = resolveFile(openMode & QIODevice::WriteOnly); + if (!openFile_) + return false; + + position_ = 0; + if (openMode & QIODevice::ReadOnly) + openForRead_ = true; + + if (openMode & QIODevice::WriteOnly) { + openForWrite_ = true; + + QMutexLocker lock(&openFile_->mutex); + if (openMode & QIODevice::Truncate + || !(openForRead_ || openMode & QIODevice::Append)) + openFile_->content.clear(); + + if (openMode & QIODevice::Append) + position_ = openFile_->content.size(); + } + + return true; + } + + bool close() + { + openFile_.clear(); + + openForRead_ = false; + openForWrite_ = false; + position_ = -1; + + return true; + } + + qint64 size() const + { + QSharedPointer<File> file = resolveFile(false); + if (!file) + return 0; + + QMutexLocker lock(&file->mutex); + return file->content.size(); + } + + qint64 pos() const + { + Q_ASSERT(openForRead_ || openForWrite_); + return position_; + } + + bool seek(qint64 pos) + { + Q_ASSERT(openForRead_ || openForWrite_); + + if (pos >= 0) { + position_ = pos; + return true; + } + + return false; + } + + bool flush() + { + Q_ASSERT(openForRead_ || openForWrite_); + return true; + } + + bool remove() + { + QMutexLocker lock(&fileSystemMutex); + int count = fileSystem.remove(fileName_); + + return (count == 1); + } + + bool copy(const QString &newName) + { + QMutexLocker lock(&fileSystemMutex); + if (!fileSystem.contains(fileName_) + || fileSystem.contains(newName)) + return false; + + fileSystem.insert(newName, fileSystem.value(fileName_)); + return true; + } + + bool rename(const QString &newName) + { + QMutexLocker lock(&fileSystemMutex); + if (!fileSystem.contains(fileName_) + || fileSystem.contains(newName)) + return false; + + fileSystem.insert(newName, fileSystem.take(fileName_)); + return true; + } + + // bool link(const QString &newName) + // { + // Q_UNUSED(newName) + // return false; + // } + + // bool mkdir(const QString &dirName, bool createParentDirectories) const + // { + // Q_UNUSED(dirName) + // Q_UNUSED(createParentDirectories) + + // return false; + // } + + // bool rmdir(const QString &dirName, bool recurseParentDirectories) const + // { + // Q_UNUSED(dirName) + // Q_UNUSED(recurseParentDirectories) + + // return false; + // } + + bool setSize(qint64 size) + { + if (size < 0) + return false; + + QSharedPointer<File> file = resolveFile(false); + if (!file) + return false; + + QMutexLocker lock(&file->mutex); + file->content.resize(size); + + if (openForRead_ || openForWrite_) + if (position_ > size) + position_ = size; + + return (file->content.size() == size); + } + + FileFlags fileFlags(FileFlags type) const + { + QSharedPointer<File> file = resolveFile(false); + if (file) { + QMutexLocker lock(&file->mutex); + return (file->fileFlags & type); + } + + return FileFlags(); + } + + // bool setPermissions(uint perms) + // { + // Q_UNUSED(perms) + + // return false; + // } + + QString fileName(FileName file) const + { + switch (file) { + case DefaultName: + return QLatin1String("DefaultName"); + case BaseName: + return QLatin1String("BaseName"); + case PathName: + return QLatin1String("PathName"); + case AbsoluteName: + return QLatin1String("AbsoluteName"); + case AbsolutePathName: + return QLatin1String("AbsolutePathName"); + case LinkName: + return QLatin1String("LinkName"); + case CanonicalName: + return QLatin1String("CanonicalName"); + case CanonicalPathName: + return QLatin1String("CanonicalPathName"); + case BundleName: + return QLatin1String("BundleName"); + + default: + break; + } + + return QString(); + } + + uint ownerId(FileOwner owner) const + { + QSharedPointer<File> file = resolveFile(false); + if (file) { + switch (owner) { + case OwnerUser: + { + QMutexLocker lock(&file->mutex); + return file->userId; + } + case OwnerGroup: + { + QMutexLocker lock(&file->mutex); + return file->groupId; + } + } + } + + return -2; + } + + QString owner(FileOwner owner) const + { + QSharedPointer<File> file = resolveFile(false); + if (file) { + uint ownerId; + switch (owner) { + case OwnerUser: + { + QMutexLocker lock(&file->mutex); + ownerId = file->userId; + } + + { + QMutexLocker lock(&fileSystemMutex); + return fileSystemUsers.value(ownerId); + } + + case OwnerGroup: + { + QMutexLocker lock(&file->mutex); + ownerId = file->groupId; + } + + { + QMutexLocker lock(&fileSystemMutex); + return fileSystemGroups.value(ownerId); + } + } + } + + return QString(); + } + + QDateTime fileTime(FileTime time) const + { + QSharedPointer<File> file = resolveFile(false); + if (file) { + QMutexLocker lock(&file->mutex); + switch (time) { + case CreationTime: + return file->creation; + case ModificationTime: + return file->modification; + case AccessTime: + return file->access; + } + } + + return QDateTime(); + } + + void setFileName(const QString &file) + { + Q_ASSERT(!openForRead_); + Q_ASSERT(!openForWrite_); + + fileName_ = file; + } + + // typedef QAbstractFileEngineIterator Iterator; + // Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) + // { + // Q_UNUSED(filters) + // Q_UNUSED(filterNames) + + // return 0; + // } + + // Iterator *endEntryList() + // { + // return 0; + // } + + qint64 read(char *data, qint64 maxLen) + { + Q_ASSERT(openForRead_); + + Q_ASSERT(!openFile_.isNull()); + QMutexLocker lock(&openFile_->mutex); + qint64 readSize = qMin(openFile_->content.size() - position_, maxLen); + if (readSize < 0) + return -1; + + qMemCopy(data, openFile_->content.constData() + position_, readSize); + position_ += readSize; + + return readSize; + } + + qint64 write(const char *data, qint64 length) + { + Q_ASSERT(openForWrite_); + + if (length < 0) + return -1; + + Q_ASSERT(!openFile_.isNull()); + QMutexLocker lock(&openFile_->mutex); + if (openFile_->content.size() == position_) + openFile_->content.append(data, length); + else { + if (position_ + length > openFile_->content.size()) + openFile_->content.resize(position_ + length); + openFile_->content.replace(position_, length, data, length); + } + + qint64 writeSize = qMin(length, openFile_->content.size() - position_); + position_ += writeSize; + + return writeSize; + } + +protected: + // void setError(QFile::FileError error, const QString &str); + + struct File + { + File() + : userId(0) + , groupId(0) + , fileFlags( + ReadOwnerPerm | WriteOwnerPerm | ExeOwnerPerm + | ReadUserPerm | WriteUserPerm | ExeUserPerm + | ReadGroupPerm | WriteGroupPerm | ExeGroupPerm + | ReadOtherPerm | WriteOtherPerm | ExeOtherPerm + | FileType | ExistsFlag) + { + } + + QMutex mutex; + + uint userId, groupId; + QAbstractFileEngine::FileFlags fileFlags; + QDateTime creation, modification, access; + + QByteArray content; + }; + + QSharedPointer<File> resolveFile(bool create) const + { + if (openForRead_ || openForWrite_) { + Q_ASSERT(openFile_); + return openFile_; + } + + QMutexLocker lock(&fileSystemMutex); + if (create) { + QSharedPointer<File> &p = fileSystem[fileName_]; + if (p.isNull()) + p = QSharedPointer<File>(new File); + return p; + } + + return fileSystem.value(fileName_); + } + + static QMutex fileSystemMutex; + static QHash<uint, QString> fileSystemUsers, fileSystemGroups; + static QHash<QString, QSharedPointer<File> > fileSystem; + +private: + QString fileName_; + qint64 position_; + bool openForRead_; + bool openForWrite_; + + mutable QSharedPointer<File> openFile_; +}; + +QMutex ReferenceFileEngine::fileSystemMutex; +QHash<uint, QString> ReferenceFileEngine::fileSystemUsers, ReferenceFileEngine::fileSystemGroups; +QHash<QString, QSharedPointer<ReferenceFileEngine::File> > ReferenceFileEngine::fileSystem; + +class FileEngineHandler + : QAbstractFileEngineHandler +{ + QAbstractFileEngine *create(const QString &fileName) const + { + if (fileName.startsWith("QFSFileEngine:")) + return new QFSFileEngine(fileName.mid(14)); + if (fileName.startsWith("reference-file-engine:")) + return new ReferenceFileEngine(fileName.mid(22)); + if (fileName.startsWith("resource:")) + return QAbstractFileEngine::create(QLatin1String(":/tst_qabstractfileengine/resources/") + fileName.mid(9)); + return 0; + } +}; + +void tst_QAbstractFileEngine::cleanupTestCase() +{ + bool failed = false; + + FileEngineHandler handler; + Q_FOREACH(QString file, filesForRemoval) + if (!QFile::remove(file) + || QFile::exists(file)) { + failed = true; + qDebug() << "Couldn't remove file:" << file; + } + + QVERIFY(!failed); +} + +void tst_QAbstractFileEngine::customHandler() +{ + QScopedPointer<QAbstractFileEngine> file; + { + file.reset(QAbstractFileEngine::create("resource:file.txt")); + + QVERIFY(file); + } + + { + FileEngineHandler handler; + + QFile file("resource:file.txt"); + QVERIFY(file.exists()); + } + + { + QFile file("resource:file.txt"); + QVERIFY(!file.exists()); + } +} + +void tst_QAbstractFileEngine::fileIO_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("readContent"); + QTest::addColumn<QByteArray>("writeContent"); + QTest::addColumn<bool>("fileExists"); + + QString resourceTxtFile(":/tst_qabstractfileengine/resources/file.txt"); + QByteArray readContent("This is a simple text file.\n"); + QByteArray writeContent("This contains two lines of text.\n"); + + QTest::newRow("resource") << resourceTxtFile << readContent << QByteArray() << true; + QTest::newRow("native") << "native-file.txt" << readContent << writeContent << false; + QTest::newRow("Forced QFSFileEngine") << "QFSFileEngine:QFSFileEngine-file.txt" << readContent << writeContent << false; + QTest::newRow("Custom FE") << "reference-file-engine:file.txt" << readContent << writeContent << false; + + QTest::newRow("Forced QFSFileEngine (native)") << "QFSFileEngine:native-file.txt" << readContent << writeContent << true; + QTest::newRow("native (Forced QFSFileEngine)") << "QFSFileEngine-file.txt" << readContent << writeContent << true; + QTest::newRow("Custom FE (2)") << "reference-file-engine:file.txt" << readContent << writeContent << true; +} + +void tst_QAbstractFileEngine::fileIO() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, readContent); + QFETCH(QByteArray, writeContent); + QFETCH(bool, fileExists); + + FileEngineHandler handler; + + + { + QFile file(fileName); + QCOMPARE(file.exists(), fileExists); + + if (!fileExists) { + QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Unbuffered)); + filesForRemoval.append(fileName); + + QCOMPARE(file.write(readContent), qint64(readContent.size())); + } + } + + // + // File content is: readContent + // + + qint64 fileSize = readContent.size(); + { + // Reading + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), qint64(0)); + + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.readAll(), readContent); + QCOMPARE(file.pos(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + if (writeContent.isEmpty()) + return; + + { + // Writing / appending + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), fileSize); + + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + + fileSize += writeContent.size(); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: readContent + writeContent + // + + { + // Reading and Writing + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::ReadWrite | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), qint64(0)); + + QCOMPARE(file.readAll(), readContent + writeContent); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.seek(writeContent.size())); + QCOMPARE(file.pos(), qint64(writeContent.size())); + QCOMPARE(file.size(), fileSize); + + QCOMPARE(file.write(readContent), qint64(readContent.size())); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.seek(0)); + QCOMPARE(file.pos(), qint64(0)); + QCOMPARE(file.size(), fileSize); + + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + QCOMPARE(file.pos(), qint64(writeContent.size())); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.seek(0)); + QCOMPARE(file.read(writeContent.size()), writeContent); + QCOMPARE(file.pos(), qint64(writeContent.size())); + QCOMPARE(file.size(), fileSize); + + QCOMPARE(file.readAll(), readContent); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: writeContent + readContent + // + + { + // Writing + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::ReadWrite | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), qint64(0)); + + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + QCOMPARE(file.pos(), qint64(writeContent.size())); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.resize(writeContent.size())); + QCOMPARE(file.size(), qint64(writeContent.size())); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), qint64(writeContent.size())); + + QVERIFY(file.resize(fileSize)); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: writeContent + <undefined> + // File size is : (readContent + writeContent).size() + // + + { + // Writing / extending + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::ReadWrite | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), qint64(0)); + + QVERIFY(file.seek(1024)); + QCOMPARE(file.pos(), qint64(1024)); + QCOMPARE(file.size(), fileSize); + + fileSize = 1024 + writeContent.size(); + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.seek(1028)); + QCOMPARE(file.pos(), qint64(1028)); + QCOMPARE(file.size(), fileSize); + + fileSize = 1028 + writeContent.size(); + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: writeContent + <undefined> + writeContent + // File size is : 1024 + writeContent.size() + // + + { + // Writing / truncating + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), qint64(0)); + QCOMPARE(file.pos(), qint64(0)); + + fileSize = readContent.size(); + QCOMPARE(file.write(readContent), fileSize); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: readContent + // +} + +QTEST_APPLESS_MAIN(tst_QAbstractFileEngine) +#include "tst_qabstractfileengine.moc" + diff --git a/tests/auto/qapplication/test/test.pro b/tests/auto/qapplication/test/test.pro index 4c8e9b0..73799f4 100644 --- a/tests/auto/qapplication/test/test.pro +++ b/tests/auto/qapplication/test/test.pro @@ -8,7 +8,7 @@ wince* { additional.path = desktopsettingsaware someTest.files = test.pro someTest.path = test - DEPLOYMENT = additional deploy someTest + DEPLOYMENT += additional deploy someTest } symbian: { @@ -17,7 +17,7 @@ symbian: { someTest.files = test.pro someTest.path = test windowIcon.files = ../heart.svg - DEPLOYMENT = additional deploy someTest windowIcon + DEPLOYMENT += additional deploy someTest windowIcon LIBS += -lcone -lavkon } diff --git a/tests/auto/qaudioinput/qaudioinput.pro b/tests/auto/qaudioinput/qaudioinput.pro index 922c3e4..aac7fb4 100644 --- a/tests/auto/qaudioinput/qaudioinput.pro +++ b/tests/auto/qaudioinput/qaudioinput.pro @@ -6,7 +6,7 @@ QT = core multimedia wince* { deploy.files += 4.wav - DEPLOYMENT = deploy + DEPLOYMENT += deploy DEFINES += SRCDIR=\\\"\\\" QT += gui } else { diff --git a/tests/auto/qaudiooutput/qaudiooutput.pro b/tests/auto/qaudiooutput/qaudiooutput.pro index 0bd0151..f4d840a 100644 --- a/tests/auto/qaudiooutput/qaudiooutput.pro +++ b/tests/auto/qaudiooutput/qaudiooutput.pro @@ -6,7 +6,7 @@ QT = core multimedia wince*|symbian: { deploy.files += 4.wav - DEPLOYMENT = deploy + DEPLOYMENT += deploy !symbian { DEFINES += SRCDIR=\\\"\\\" QT += gui diff --git a/tests/auto/qchar/qchar.pro b/tests/auto/qchar/qchar.pro index 9fcf132..1681220 100644 --- a/tests/auto/qchar/qchar.pro +++ b/tests/auto/qchar/qchar.pro @@ -5,7 +5,7 @@ QT = core wince*|symbian: { deploy.files += NormalizationTest.txt -DEPLOYMENT = deploy +DEPLOYMENT += deploy } symbian: { diff --git a/tests/auto/qclipboard/test/test.pro b/tests/auto/qclipboard/test/test.pro index 6e61b31..12c6b6c 100644 --- a/tests/auto/qclipboard/test/test.pro +++ b/tests/auto/qclipboard/test/test.pro @@ -28,5 +28,5 @@ wince*|symbian: { reg_resource.path = $$REG_RESOURCE_IMPORT_DIR } - DEPLOYMENT = copier paster rsc reg_resource + DEPLOYMENT += copier paster rsc reg_resource }
\ No newline at end of file diff --git a/tests/auto/qdir/qdir.pro b/tests/auto/qdir/qdir.pro index 818f52c..472e646 100644 --- a/tests/auto/qdir/qdir.pro +++ b/tests/auto/qdir/qdir.pro @@ -15,8 +15,11 @@ wince* { TARGET.CAPABILITY += AllFiles TARGET.UID3 = 0xE0340002 DEFINES += SYMBIAN_SRCDIR_UID=$$lower($$replace(TARGET.UID3,"0x","")) + LIBS += -lefsrv + INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE } else { contains(QT_CONFIG, qt3support):QT += qt3support DEFINES += SRCDIR=\\\"$$PWD/\\\" } +CONFIG += parallel_test diff --git a/tests/auto/qdir/tst_qdir.cpp b/tests/auto/qdir/tst_qdir.cpp index 9678868..dc46f52 100644 --- a/tests/auto/qdir/tst_qdir.cpp +++ b/tests/auto/qdir/tst_qdir.cpp @@ -57,11 +57,13 @@ #include "../../shared/filesystem.h" #if defined(Q_OS_SYMBIAN) +# include <f32file.h> # define STRINGIFY(x) #x # define TOSTRING(x) STRINGIFY(x) # define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID) "/" #elif defined(Q_OS_UNIX) # include <unistd.h> +# include <sys/stat.h> #endif #if defined(Q_OS_VXWORKS) @@ -69,7 +71,7 @@ #endif #if defined(Q_OS_SYMBIAN) -// Open C in Symbian doesn't support symbolic links to directories +#define Q_NO_SYMLINKS #define Q_NO_SYMLINKS_TO_DIRS #endif @@ -103,6 +105,8 @@ private slots: void mkdir_data(); void mkdir(); + void makedirReturnCode(); + void rmdir_data(); void rmdir(); @@ -175,10 +179,31 @@ private slots: void detachingOperations(); -#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + void testCaching(); + void isRoot_data(); void isRoot(); + +#ifndef QT_NO_REGEXP + void match_data(); + void match(); +#endif + + void drives(); + + void arrayOperator(); + +#ifdef QT3_SUPPORT + void setNameFilter(); #endif + + void equalityOperator_data(); + void equalityOperator(); + + void isRelative_data(); + void isRelative(); + + void isReadable(); }; // Testing get/set functions @@ -293,6 +318,17 @@ void tst_QDir::mkdir() QVERIFY(fi.exists() && fi.isDir()); } +void tst_QDir::makedirReturnCode() +{ + QString dirName = QString::fromLatin1("makedirReturnCode"); + QDir::current().rmdir(dirName); // cleanup a previous run. + QDir dir(dirName); + QVERIFY(!dir.exists()); + QVERIFY(QDir::current().mkdir(dirName)); + QVERIFY(!QDir::current().mkdir(dirName)); // calling mkdir on an existing dir will fail. + QVERIFY(QDir::current().mkpath(dirName)); // calling mkpath on an existing dir will pass +} + void tst_QDir::rmdir_data() { QTest::addColumn<QString>("path"); @@ -597,6 +633,7 @@ void tst_QDir::entryList() expected.removeAll(".."); #endif +#ifndef Q_NO_SYMLINKS #if defined(Q_OS_WIN) // ### Sadly, this is a platform difference right now. QFile::link(SRCDIR "entryList/file", SRCDIR "entrylist/linktofile.lnk"); @@ -651,6 +688,7 @@ void tst_QDir::entryList() QFile::link("directory", SRCDIR "entrylist/linktodirectory.lnk"); QFile::link("nothing", SRCDIR "entrylist/brokenlink.lnk"); #endif +#endif //Q_NO_SYMLINKS #ifdef Q_WS_MAC if (qstrcmp(QTest::currentDataTag(), "unprintablenames") == 0) @@ -813,11 +851,11 @@ void tst_QDir::canonicalPath_data() #endif QTest::newRow("nonexistant") << "testd" << QString(); + QTest::newRow("rootPath") << QDir::rootPath() << QDir::rootPath(); + QTest::newRow("rootPath + ./") << QDir::rootPath().append("./") << QDir::rootPath(); + QTest::newRow("rootPath + ../.. ") << QDir::rootPath().append("../..") << QDir::rootPath(); #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) - QTest::newRow("drive:/") << QDir::rootPath() << QDir::rootPath(); QTest::newRow("drive:\\") << QDir::toNativeSeparators(QDir::rootPath()) << QDir::rootPath(); - QTest::newRow("drive:/./") << QDir::rootPath().append("./") << QDir::rootPath(); - QTest::newRow("drive:/../.. ") << QDir::rootPath().append("../..") << QDir::rootPath(); QTest::newRow("drive:\\.\\") << QDir::toNativeSeparators(QDir::rootPath().append("./")) << QDir::rootPath(); QTest::newRow("drive:\\..\\..") << QDir::toNativeSeparators(QDir::rootPath().append("../..")) << QDir::rootPath(); QTest::newRow("drive:") << QDir().canonicalPath().left(2) << QDir().canonicalPath(); @@ -890,7 +928,7 @@ void tst_QDir::current() if (!path.isEmpty()) { bool b = QDir::setCurrent(path); - // If path is non existant, then setCurrent should be false (currentDir is empty in testData) + // If path is non existent, then setCurrent should be false (currentDir is empty in testData) QVERIFY(b == !currentDir.isEmpty()); } if (!currentDir.isEmpty()) { @@ -935,6 +973,7 @@ void tst_QDir::cd() QFETCH(QString, newDir); QDir d = startDir; + bool notUsed = d.exists(); // make sure we cache this before so we can see if 'cd' fails to flush this QCOMPARE(d.cd(cdDir), successExpected); if (successExpected) QCOMPARE(d.absolutePath(), newDir); @@ -1104,24 +1143,24 @@ void tst_QDir::relativeFilePath_data() QTest::newRow("14") << "C:/foo/bar" << "/ding/dong" << "../../ding/dong"; QTest::newRow("15") << "C:/foo/bar" << "D:/ding/dong" << "D:/ding/dong"; QTest::newRow("16") << "C:" << "C:/ding/dong" << "ding/dong"; - QTest::newRow("16") << "C:/" << "C:/ding/dong" << "ding/dong"; - QTest::newRow("17") << "C:" << "C:" << ""; - QTest::newRow("18") << "C:/" << "C:" << ""; - QTest::newRow("19") << "C:" << "C:/" << ""; - QTest::newRow("20") << "C:/" << "C:/" << ""; - QTest::newRow("17") << "C:" << "C:file.txt" << "file.txt"; - QTest::newRow("18") << "C:/" << "C:file.txt" << "file.txt"; - QTest::newRow("19") << "C:" << "C:/file.txt" << "file.txt"; - QTest::newRow("20") << "C:/" << "C:/file.txt" << "file.txt"; - QTest::newRow("21") << "C:" << "D:" << "D:"; - QTest::newRow("22") << "C:" << "D:/" << "D:/"; - QTest::newRow("23") << "C:/" << "D:" << "D:"; - QTest::newRow("24") << "C:/" << "D:/" << "D:/"; + QTest::newRow("17") << "C:/" << "C:/ding/dong" << "ding/dong"; + QTest::newRow("18") << "C:" << "C:" << ""; + QTest::newRow("19") << "C:/" << "C:" << ""; + QTest::newRow("20") << "C:" << "C:/" << ""; + QTest::newRow("21") << "C:/" << "C:/" << ""; + QTest::newRow("22") << "C:" << "C:file.txt" << "file.txt"; + QTest::newRow("23") << "C:/" << "C:file.txt" << "file.txt"; + QTest::newRow("24") << "C:" << "C:/file.txt" << "file.txt"; + QTest::newRow("25") << "C:/" << "C:/file.txt" << "file.txt"; + QTest::newRow("26") << "C:" << "D:" << "D:"; + QTest::newRow("27") << "C:" << "D:/" << "D:/"; + QTest::newRow("28") << "C:/" << "D:" << "D:"; + QTest::newRow("29") << "C:/" << "D:/" << "D:/"; # if !defined(Q_OS_SYMBIAN) - QTest::newRow("25") << "C:/foo/bar" << "//anotherHost/foo/bar" << "//anotherHost/foo/bar"; - QTest::newRow("26") << "//anotherHost/foo" << "//anotherHost/foo/bar" << "bar"; - QTest::newRow("27") << "//anotherHost/foo" << "bar" << "bar"; - QTest::newRow("28") << "//anotherHost/foo" << "C:/foo/bar" << "C:/foo/bar"; + QTest::newRow("30") << "C:/foo/bar" << "//anotherHost/foo/bar" << "//anotherHost/foo/bar"; + QTest::newRow("31") << "//anotherHost/foo" << "//anotherHost/foo/bar" << "bar"; + QTest::newRow("32") << "//anotherHost/foo" << "bar" << "bar"; + QTest::newRow("33") << "//anotherHost/foo" << "C:/foo/bar" << "C:/foo/bar"; # endif #endif } @@ -1167,6 +1206,8 @@ void tst_QDir::remove() QDir dir; QVERIFY(dir.remove("remove-test")); QVERIFY(!dir.remove("/remove-test")); + QTest::ignoreMessage(QtWarningMsg, "QDir::remove: Empty or null file name"); + QVERIFY(!dir.remove("")); } void tst_QDir::rename() @@ -1179,10 +1220,18 @@ void tst_QDir::rename() QVERIFY(dir.rename("rename-test-renamed", "rename-test")); #if defined(Q_OS_MAC) QVERIFY(!dir.rename("rename-test", "/etc/rename-test-renamed")); -#elif !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - // on windows/symbian this is possible - maybe make the test a bit better +#elif defined(Q_OS_SYMBIAN) + QVERIFY(!dir.rename("rename-test", "/resource/rename-test-renamed")); +#elif !defined(Q_OS_WIN) + // on windows this is possible - maybe make the test a bit better QVERIFY(!dir.rename("rename-test", "/rename-test-renamed")); #endif + QTest::ignoreMessage(QtWarningMsg, "QDir::rename: Empty or null file name(s)"); + QVERIFY(!dir.rename("rename-test", "")); + QTest::ignoreMessage(QtWarningMsg, "QDir::rename: Empty or null file name(s)"); + QVERIFY(!dir.rename("", "rename-test-renamed")); + QVERIFY(!dir.rename("some-file-that-does-not-exist", "rename-test-renamed")); + QVERIFY(dir.remove("rename-test")); } @@ -1256,12 +1305,13 @@ void tst_QDir::dotAndDotDot() { #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) QSKIP("WinCE and Symbian do not have . nor ..", SkipAll); -#endif +#else QDir dir(QString(SRCDIR "testdir/")); QStringList entryList = dir.entryList(QDir::Dirs); QCOMPARE(entryList, QStringList() << QString(".") << QString("..") << QString("dir") << QString("spaces")); entryList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); QCOMPARE(entryList, QStringList() << QString("dir") << QString("spaces")); +#endif } #ifdef QT3_SUPPORT @@ -1416,6 +1466,29 @@ void tst_QDir::searchPaths() for (int i = 0; i < searchPathPrefixList.count(); ++i) { QVERIFY(QDir::searchPaths(searchPathPrefixList.at(i)).isEmpty()); } + + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + foreach (QString path, searchPathsList.at(i).split(",")) { + QDir::addSearchPath(searchPathPrefixList.at(i), path); + } + } + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QVERIFY(QDir::searchPaths(searchPathPrefixList.at(i)) == searchPathsList.at(i).split(",")); + } + + QCOMPARE(QFile(filename).exists(), exists); + QCOMPARE(QFileInfo(filename).exists(), exists); + + if (exists) { + QCOMPARE(QFileInfo(filename).absoluteFilePath(), expectedAbsolutePath); + } + + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QDir::setSearchPaths(searchPathPrefixList.at(i), QStringList()); + } + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QVERIFY(QDir::searchPaths(searchPathPrefixList.at(i)).isEmpty()); + } } void tst_QDir::entryListWithSearchPaths() @@ -1660,7 +1733,17 @@ void tst_QDir::detachingOperations() QCOMPARE(dir1.sorting(), sorting); } -#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +void tst_QDir::testCaching() +{ + QString dirName = QString::fromLatin1("testCaching"); + QDir::current().rmdir(dirName); // cleanup a previous run. + QDir dir(dirName); + QVERIFY(!dir.exists()); + QDir::current().mkdir(dirName); + QVERIFY(QDir(dirName).exists()); // dir exists + QVERIFY(dir.exists()); // QDir doesn't cache the 'exist' between calls. +} + void tst_QDir::isRoot_data() { QTest::addColumn<QString>("path"); @@ -1672,8 +1755,13 @@ void tst_QDir::isRoot_data() QTest::newRow(QString("./ appended " + test).toLatin1()) << test << false; test = QDir(QDir::rootPath().append("./")).canonicalPath(); QTest::newRow(QString("canonicalPath " + test).toLatin1()) << test << true; +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) test = QDir::rootPath().left(2); QTest::newRow(QString("drive relative " + test).toLatin1()) << test << false; +#endif + + QTest::newRow("resources root") << ":/" << true; + QTest::newRow("resources nonroot") << ":/entrylist" << false; } void tst_QDir::isRoot() @@ -1684,8 +1772,203 @@ void tst_QDir::isRoot() QDir dir(path); QCOMPARE(dir.isRoot(),isRoot); } + +#ifndef QT_NO_REGEXP +void tst_QDir::match_data() +{ + QTest::addColumn<QString>("filter"); + QTest::addColumn<QString>("filename"); + QTest::addColumn<bool>("match"); + + QTest::newRow("single, matching") << "*.cpp" << "tst_qdir.cpp" << true; + QTest::newRow("single, not matching") << "*.cpp" << "tst_qdir.h" << false; + QTest::newRow("multi, matching") << "*.cpp;*.h" << "tst_qdir.cpp" << true; + QTest::newRow("multi, matching2") << "*.cpp;*.h" << "tst_qdir.h" << true; + QTest::newRow("multi, not matching") << "*.cpp;*.h" << "readme.txt" << false; +} + +void tst_QDir::match() +{ + QFETCH(QString, filter); + QFETCH(QString, filename); + QFETCH(bool, match); + + QCOMPARE(QDir::match(filter, filename), match); + QCOMPARE(QDir::match(filter.split(QLatin1Char(';')), filename), match); +} #endif +void tst_QDir::drives() +{ + QFileInfoList list(QDir::drives()); +#if defined(Q_OS_WIN) + QVERIFY(list.count() >= 1); //system + QLatin1Char systemdrive('c'); +#elif defined(Q_OS_SYMBIAN) + QVERIFY(list.count() >= 2); //system, rom + QLatin1Char romdrive('z'); + QLatin1Char systemdrive('a' + int(RFs::GetSystemDrive())); +#endif +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QVERIFY(list.count() <= 26); + bool foundsystem = false; +#ifdef Q_OS_SYMBIAN + bool foundrom = false; +#endif + foreach (QFileInfo fi, list) { + QCOMPARE(fi.absolutePath().size(), 3); //"x:/" + QCOMPARE(fi.absolutePath().at(1), QChar(QLatin1Char(':'))); + QCOMPARE(fi.absolutePath().at(2), QChar(QLatin1Char('/'))); + if (fi.absolutePath().at(0).toLower() == systemdrive) + foundsystem = true; +#ifdef Q_OS_SYMBIAN + if (fi.absolutePath().at(0).toLower() == romdrive) + foundrom = true; +#endif + } + QCOMPARE(foundsystem, true); +#ifdef Q_OS_SYMBIAN + QCOMPARE(foundrom, true); +#endif +#else + QCOMPARE(list.count(), 1); //root + QCOMPARE(list.at(0).absolutePath(), QLatin1String("/")); +#endif +} + +void tst_QDir::arrayOperator() +{ + QDir dir1(SRCDIR "entrylist/"); + QDir dir2(SRCDIR "entrylist/"); + + QStringList entries(dir1.entryList()); + int i = dir2.count(); + QCOMPARE(i, entries.count()); + --i; + for (;i>=0;--i) { + QCOMPARE(dir2[i], entries.at(i)); + } +} + +#ifdef QT3_SUPPORT +void tst_QDir::setNameFilter() +{ + QStringList filters; + filters << "*.jpg" << "*.png" << "*.gif"; + QStringList filters2; + filters2 << "*.cpp" << "*.h" << "*.c"; + + QDir dir(SRCDIR "entrylist/"); + + dir.setNameFilter(filters.join(";")); + QCOMPARE(filters, dir.nameFilters()); + QCOMPARE(filters, dir.nameFilter().split(';')); + + dir.setNameFilters(filters2); + QCOMPARE(filters2, dir.nameFilter().split(';')); + + dir.setNameFilter(filters.join(" ")); + QCOMPARE(filters, dir.nameFilters()); + QCOMPARE(filters, dir.nameFilter().split(' ')); + + dir.setNameFilters(filters2); + QCOMPARE(filters2, dir.nameFilter().split(' ')); +} +#endif + +void tst_QDir::equalityOperator_data() +{ + QTest::addColumn<QString>("leftPath"); + QTest::addColumn<QString>("leftNameFilters"); + QTest::addColumn<int>("leftSort"); + QTest::addColumn<int>("leftFilters"); + QTest::addColumn<QString>("rightPath"); + QTest::addColumn<QString>("rightNameFilters"); + QTest::addColumn<int>("rightSort"); + QTest::addColumn<int>("rightFilters"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("same") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << true; + + QTest::newRow("relativepaths") << "entrylist/" << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << "./entrylist" << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << true; + + QTest::newRow("diff-filters") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Dirs) + << false; + + QTest::newRow("diff-sort") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << SRCDIR << "*.cpp" << int(QDir::Time) << int(QDir::Files) + << false; + + QTest::newRow("diff-namefilters") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << SRCDIR << "*.jpg" << int(QDir::Name) << int(QDir::Files) + << false; +} + +void tst_QDir::equalityOperator() +{ + QFETCH(QString, leftPath); + QFETCH(QString, leftNameFilters); + QFETCH(int, leftSort); + QFETCH(int, leftFilters); + QFETCH(QString, rightPath); + QFETCH(QString, rightNameFilters); + QFETCH(int, rightSort); + QFETCH(int, rightFilters); + QFETCH(bool, expected); + + QDir dir1(leftPath, leftNameFilters, QDir::SortFlags(leftSort), QDir::Filters(leftFilters)); + QDir dir2(rightPath, rightNameFilters, QDir::SortFlags(rightSort), QDir::Filters(rightFilters)); + + QCOMPARE((dir1 == dir2), expected); + QCOMPARE((dir2 == dir1), expected); + QCOMPARE((dir1 != dir2), !expected); + QCOMPARE((dir2 != dir1), !expected); +} + +void tst_QDir::isRelative_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("relative"); + + QTest::newRow(".") << "./" << true; + QTest::newRow("..") << "../" << true; + QTest::newRow("content") << "entrylist/" << true; + QTest::newRow("current") << QDir::currentPath() << false; + QTest::newRow("homepath") << QDir::homePath() << false; + QTest::newRow("temppath") << QDir::tempPath() << false; + QTest::newRow("rootpath") << QDir::rootPath() << false; + foreach (QFileInfo root, QDir::drives()) { + QTest::newRow(root.absolutePath().toLocal8Bit()) << root.absolutePath() << false; + } +} + +void tst_QDir::isRelative() +{ + QFETCH(QString, path); + QFETCH(bool, relative); + + QCOMPARE(QDir(path).isRelative(), relative); +} + +void tst_QDir::isReadable() +{ + QDir dir; + + QVERIFY(dir.isReadable()); +#if defined (Q_OS_UNIX) && !defined (Q_OS_SYMBIAN) + QVERIFY(dir.mkdir("nonreadabledir")); + QVERIFY(0 == ::chmod("nonreadabledir", 0)); + QVERIFY(!QDir("nonreadabledir").isReadable()); + QVERIFY(0 == ::chmod("nonreadabledir", S_IRUSR | S_IWUSR | S_IXUSR)); + QVERIFY(dir.rmdir("nonreadabledir")); +#endif +} + QTEST_MAIN(tst_QDir) #include "tst_qdir.moc" diff --git a/tests/auto/qdiriterator/qdiriterator.pro b/tests/auto/qdiriterator/qdiriterator.pro index 140b57d..0807a18 100644 --- a/tests/auto/qdiriterator/qdiriterator.pro +++ b/tests/auto/qdiriterator/qdiriterator.pro @@ -3,11 +3,6 @@ SOURCES += tst_qdiriterator.cpp RESOURCES += qdiriterator.qrc QT = core -wince*|symbian: { - addFiles.files = entrylist recursiveDirs foo - addFiles.path = . - DEPLOYMENT += addFiles wince*mips*|wincewm50smart-msvc200*: DEFINES += WINCE_BROKEN_ITERATE=1 -} CONFIG += parallel_test diff --git a/tests/auto/qdiriterator/tst_qdiriterator.cpp b/tests/auto/qdiriterator/tst_qdiriterator.cpp index 1a873b8..3a696b5 100644 --- a/tests/auto/qdiriterator/tst_qdiriterator.cpp +++ b/tests/auto/qdiriterator/tst_qdiriterator.cpp @@ -53,10 +53,14 @@ #endif #if defined(Q_OS_SYMBIAN) -// Open C in Symbian doesn't support symbolic links to directories +#define Q_NO_SYMLINKS #define Q_NO_SYMLINKS_TO_DIRS #endif +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#include "../network-settings.h" +#endif + Q_DECLARE_METATYPE(QDirIterator::IteratorFlags) Q_DECLARE_METATYPE(QDir::Filters) @@ -118,6 +122,10 @@ private slots: void longPath(); void task185502_dirorder(); void relativePaths(); +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + void uncPaths_data(); + void uncPaths(); +#endif }; tst_QDirIterator::tst_QDirIterator() @@ -147,6 +155,8 @@ tst_QDirIterator::tst_QDirIterator() createDirectory("foo/bar"); createFile("foo/bar/readme.txt"); + createDirectory("empty"); + #ifndef Q_NO_SYMLINKS # if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) // ### Sadly, this is a platform difference right now. @@ -288,6 +298,20 @@ void tst_QDirIterator::iterateRelativeDirectory_data() #endif "entrylist/directory/dummy," "entrylist/writable").split(','); + + QTest::newRow("empty, default") + << QString("empty") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::NoFilter) << QStringList("*") +#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) + << QStringList(); +#else + << QString("empty/.,empty/..").split(','); +#endif + + QTest::newRow("empty, QDir::NoDotAndDotDot") + << QString("empty") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::NoDotAndDotDot) << QStringList("*") + << QStringList(); } void tst_QDirIterator::iterateRelativeDirectory() @@ -532,6 +556,28 @@ void tst_QDirIterator::relativePaths() } } +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +void tst_QDirIterator::uncPaths_data() +{ + QTest::addColumn<QString>("dirName"); + QTest::newRow("uncserver") + <<QString("//" + QtNetworkSettings::winServerName()); + QTest::newRow("uncserver/testshare") + <<QString("//" + QtNetworkSettings::winServerName() + "/testshare"); + QTest::newRow("uncserver/testshare/tmp") + <<QString("//" + QtNetworkSettings::winServerName() + "/testshare/tmp"); +} +void tst_QDirIterator::uncPaths() +{ + QFETCH(QString, dirName); + QDirIterator iterator(dirName, QDir::AllEntries|QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while(iterator.hasNext()) { + iterator.next(); + QCOMPARE(iterator.filePath(), QDir::cleanPath(iterator.filePath())); + } +} +#endif + QTEST_MAIN(tst_QDirIterator) #include "tst_qdiriterator.moc" diff --git a/tests/auto/qdirmodel/tst_qdirmodel.cpp b/tests/auto/qdirmodel/tst_qdirmodel.cpp index 41bbd87..e252b82 100644 --- a/tests/auto/qdirmodel/tst_qdirmodel.cpp +++ b/tests/auto/qdirmodel/tst_qdirmodel.cpp @@ -583,19 +583,15 @@ void tst_QDirModel::unreadable() void tst_QDirModel::filePath() { +#ifdef Q_OS_SYMBIAN + QSKIP("OS doesn't support symbolic links", SkipAll); +#else QFile::remove(SRCDIR "test.lnk"); QVERIFY(QFile(SRCDIR "tst_qdirmodel.cpp").link(SRCDIR "test.lnk")); QDirModel model; model.setResolveSymlinks(false); QModelIndex index = model.index(SRCDIR "test.lnk"); QVERIFY(index.isValid()); -#if defined(Q_OS_SYMBIAN) - // Since model will force lowercase path in Symbian, make case insensitive compare - // Note: Windows should fail this, too, if test path has any uppercase letters. - QCOMPARE(model.filePath(index).toLower(), QString(SRCDIR).toLower() + "test.lnk"); - model.setResolveSymlinks(true); - QCOMPARE(model.filePath(index).toLower(), QString(SRCDIR).toLower() + "tst_qdirmodel.cpp"); -#else #ifndef Q_OS_WINCE QString path = SRCDIR; #else @@ -604,8 +600,8 @@ void tst_QDirModel::filePath() QCOMPARE(model.filePath(index), path + QString( "test.lnk")); model.setResolveSymlinks(true); QCOMPARE(model.filePath(index), path + QString( "tst_qdirmodel.cpp")); -#endif QFile::remove(SRCDIR "test.lnk"); +#endif } void tst_QDirModel::task196768_sorting() @@ -613,11 +609,6 @@ void tst_QDirModel::task196768_sorting() //this task showed that the persistent model indexes got corrupted when sorting QString path = SRCDIR; -#ifdef Q_OS_SYMBIAN - if(!RProcess().HasCapability(ECapabilityAllFiles)) - QEXPECT_FAIL("", "QTBUG-9746", Continue); -#endif - QDirModel model; /* QDirModel has a bug if we show the content of the subdirectory inside a hidden directory @@ -637,6 +628,11 @@ void tst_QDirModel::task196768_sorting() QCOMPARE(index.data(), index2.data()); view.setSortingEnabled(true); index2 = model.index(path); + +#ifdef Q_OS_SYMBIAN + if(!RProcess().HasCapability(ECapabilityAllFiles)) + QEXPECT_FAIL("", "QTBUG-9746", Continue); +#endif QCOMPARE(index.data(), index2.data()); } diff --git a/tests/auto/qfile/largefile/largefile.pro b/tests/auto/qfile/largefile/largefile.pro index d67cb46..6407cb6 100644 --- a/tests/auto/qfile/largefile/largefile.pro +++ b/tests/auto/qfile/largefile/largefile.pro @@ -4,3 +4,5 @@ QT = core SOURCES += tst_largefile.cpp wince*: SOURCES += $$QT_SOURCE_TREE/src/corelib/kernel/qfunctions_wince.cpp + +CONFIG += parallel_test diff --git a/tests/auto/qfile/qfile.pro b/tests/auto/qfile/qfile.pro index 727f660..f41d327 100644 --- a/tests/auto/qfile/qfile.pro +++ b/tests/auto/qfile/qfile.pro @@ -7,3 +7,4 @@ wince*|symbian:{ !symbian:SUBDIRS += largefile +CONFIG += parallel_test diff --git a/tests/auto/qfile/test/test.pro b/tests/auto/qfile/test/test.pro index c657e9a..673eacc 100644 --- a/tests/auto/qfile/test/test.pro +++ b/tests/auto/qfile/test/test.pro @@ -10,7 +10,7 @@ wince*|symbian { resour.files += ..\\resources\\file1.ext1 resour.path = resources - DEPLOYMENT = files resour + DEPLOYMENT += files resour } wince* { diff --git a/tests/auto/qfile/tst_qfile.cpp b/tests/auto/qfile/tst_qfile.cpp index ee799f3..c19079f 100644 --- a/tests/auto/qfile/tst_qfile.cpp +++ b/tests/auto/qfile/tst_qfile.cpp @@ -170,6 +170,7 @@ private slots: void encodeName(); void truncate(); void seekToPos(); + void seekAfterEndOfFile(); void FILEReadWrite(); void i18nFileName_data(); void i18nFileName(); @@ -210,6 +211,16 @@ private slots: void openStandardStreams(); + void resize_data(); + void resize(); + + void objectConstructors(); +#ifdef Q_OS_SYMBIAN + void platformSecurity_data(); + void platformSecurity(); +#endif + void caseSensitivity(); + // --- Task related tests below this line void task167217(); @@ -394,6 +405,7 @@ void tst_QFile::cleanupTestCase() QFile::remove("qfile_map_testfile"); QFile::remove("readAllBuffer.txt"); QFile::remove("qt_file.tmp"); + QFile::remove("File.txt"); } //------------------------------------------ @@ -402,7 +414,7 @@ void tst_QFile::cleanupTestCase() // attributes and the contents itself // will be changed as far as we have a // proper way to handle files in the -// testing enviroment. +// testing environment. //------------------------------------------ void tst_QFile::exists() @@ -1108,6 +1120,7 @@ void tst_QFile::permissions() QFETCH(bool, expected); QFile f(file); QCOMPARE(((f.permissions() & perms) == QFile::Permissions(perms)), expected); + QCOMPARE(((QFile::permissions(file) & perms) == QFile::Permissions(perms)), expected); } void tst_QFile::setPermissions() @@ -1285,17 +1298,32 @@ static QString getWorkingDirectoryForLink(const QString &linkFileName) void tst_QFile::link() { +#if defined(Q_OS_SYMBIAN) + QSKIP("Symbian does not support links", SkipAll); +#endif QFile::remove("myLink.lnk"); - QFileInfo info1("tst_qfile.cpp"); - QVERIFY(QFile::link("tst_qfile.cpp", "myLink.lnk")); + + QFileInfo info1(SRCDIR "tst_qfile.cpp"); + QString referenceTarget = QDir::cleanPath(info1.absoluteFilePath()); + + QVERIFY(QFile::link(SRCDIR "tst_qfile.cpp", "myLink.lnk")); + QFileInfo info2("myLink.lnk"); QVERIFY(info2.isSymLink()); - QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath()); + QCOMPARE(info2.symLinkTarget(), referenceTarget); + + QFile link("myLink.lnk"); + QVERIFY(link.open(QIODevice::ReadOnly)); + QCOMPARE(link.symLinkTarget(), referenceTarget); + link.close(); + + QCOMPARE(QFile::symLinkTarget("myLink.lnk"), referenceTarget); #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) QString wd = getWorkingDirectoryForLink(info2.absoluteFilePath()); - QCOMPARE(QDir::fromNativeSeparators(wd), info1.absolutePath()); + QCOMPARE(QDir::fromNativeSeparators(wd), QDir::cleanPath(info1.absolutePath())); #endif + QVERIFY(QFile::remove(info2.absoluteFilePath())); } @@ -1324,6 +1352,9 @@ void tst_QFile::linkToDir() void tst_QFile::absolutePathLinkToRelativePath() { +#if defined(Q_OS_SYMBIAN) + QSKIP("Symbian does not support links", SkipAll); +#endif QFile::remove("myDir/test.txt"); QFile::remove("myDir/myLink.lnk"); QDir dir; @@ -1346,6 +1377,9 @@ void tst_QFile::absolutePathLinkToRelativePath() void tst_QFile::readBrokenLink() { +#if defined(Q_OS_SYMBIAN) + QSKIP("Symbian does not support links", SkipAll); +#endif QFile::remove("myLink2.lnk"); QFileInfo info1("file12"); #if defined(Q_OS_SYMBIAN) @@ -1635,10 +1669,40 @@ void tst_QFile::seekToPos() } +void tst_QFile::seekAfterEndOfFile() +{ + QLatin1String filename("seekAfterEof.dat"); + QFile::remove(filename); + { + QFile file(filename); + QVERIFY(file.open(QFile::WriteOnly)); + file.write("abcd"); + QCOMPARE(file.size(), qint64(4)); + file.seek(8); + file.write("ijkl"); + QCOMPARE(file.size(), qint64(12)); + file.seek(4); + file.write("efgh"); + QCOMPARE(file.size(), qint64(12)); + file.seek(16); + file.write("----"); + QCOMPARE(file.size(), qint64(20)); + file.flush(); + } + + QFile file(filename); + QVERIFY(file.open(QFile::ReadOnly)); + QByteArray contents = file.readAll(); + QCOMPARE(contents.left(12), QByteArray("abcdefghijkl", 12)); + //bytes 12-15 are uninitialised so we don't care what they read as. + QCOMPARE(contents.mid(16), QByteArray("----", 4)); + file.close(); + QFile::remove(filename); +} void tst_QFile::FILEReadWrite() { - // Tests modifing a file. First creates it then reads in 4 bytes and then overwrites these + // Tests modifying a file. First creates it then reads in 4 bytes and then overwrites these // 4 bytes with new values. At the end check to see the file contains the new values. QFile::remove("FILEReadWrite.txt"); @@ -2494,10 +2558,11 @@ void tst_QFile::standarderror() void tst_QFile::handle() { -#ifndef Q_OS_WINCE + int fd; +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) QFile file(SRCDIR "tst_qfile.cpp"); QVERIFY(file.open(QIODevice::ReadOnly)); - int fd = int(file.handle()); + fd = int(file.handle()); QVERIFY(fd > 2); QCOMPARE(int(file.handle()), fd); char c = '\0'; @@ -2524,6 +2589,7 @@ void tst_QFile::handle() QCOMPARE(c, '*'); #endif + //test round trip of adopted stdio file handle QFile file2; FILE *fp = fopen(SRCDIR "tst_qfile.cpp", "r"); file2.open(fp, QIODevice::ReadOnly); @@ -2531,6 +2597,7 @@ void tst_QFile::handle() QCOMPARE(int(file2.handle()), int(fileno(fp))); fclose(fp); + //test round trip of adopted posix file handle #ifdef Q_OS_UNIX QFile file3; fd = QT_OPEN(SRCDIR "tst_qfile.cpp", QT_OPEN_RDONLY); @@ -2542,6 +2609,9 @@ void tst_QFile::handle() void tst_QFile::nativeHandleLeaks() { +#ifdef Q_OS_SYMBIAN + QSKIP("test assumptions invalid for symbian", SkipAll); +#else int fd1, fd2; #ifdef Q_OS_WIN @@ -2583,6 +2653,7 @@ void tst_QFile::nativeHandleLeaks() #ifdef Q_OS_WIN QCOMPARE( handle2, handle1 ); #endif +#endif } void tst_QFile::readEof_data() @@ -2898,6 +2969,7 @@ void tst_QFile::mapOpenMode() { QFETCH(int, openMode); static const qint64 fileSize = 4096; + QByteArray pattern(fileSize, 'A'); QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile"; @@ -3037,5 +3109,123 @@ void tst_QFile::writeNothing() } } +void tst_QFile::resize_data() +{ + QTest::addColumn<int>("filetype"); + + QTest::newRow("native") << int(OpenQFile); + QTest::newRow("fileno") << int(OpenFd); + QTest::newRow("stream") << int(OpenStream); +} + +void tst_QFile::resize() +{ + QFETCH(int, filetype); + QString filename(QLatin1String("file.txt")); + QFile file(filename); + QVERIFY(openFile(file, QIODevice::ReadWrite, FileType(filetype))); + QVERIFY(file.resize(8)); + QCOMPARE(file.size(), qint64(8)); + closeFile(file); + QFile::resize(filename, 4); + QCOMPARE(QFileInfo(filename).size(), qint64(4)); + QVERIFY(QFile::remove(filename)); +} + +void tst_QFile::objectConstructors() +{ + QObject ob; + QFile* file1 = new QFile(SRCDIR "testfile.txt", &ob); + QFile* file2 = new QFile(&ob); + QVERIFY(file1->exists()); + QVERIFY(!file2->exists()); +} + +#ifdef Q_OS_SYMBIAN +void tst_QFile::platformSecurity_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<bool>("readable"); + QTest::addColumn<bool>("writable"); + + QString selfname = QCoreApplication::applicationFilePath(); + QString ownprivate = QCoreApplication::applicationDirPath(); + QString owndrive = selfname.left(2); + bool amiprivileged = RProcess().HasCapability(ECapabilityAllFiles); + QTest::newRow("resource") << owndrive + "/resource/apps/tst_qfile.rsc" << true << amiprivileged; + QTest::newRow("sys") << selfname << amiprivileged << false; + QTest::newRow("own private") << ownprivate + "/testfile.txt" << true << true; + QTest::newRow("other private") << owndrive + "/private/10003a3f/import/apps/tst_qfile_reg.rsc" << amiprivileged << amiprivileged; +} + +void tst_QFile::platformSecurity() +{ + QFETCH(QString,file); + QFETCH(bool,readable); + QFETCH(bool,writable); + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::ReadOnly), readable); + } + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::ReadOnly | QIODevice::Unbuffered), readable); + } + + //append mode used to avoid truncating the files. + { + QFile f(file); + QCOMPARE(f.open(QIODevice::WriteOnly | QIODevice::Append), writable); + } + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered), writable); + } + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::ReadWrite), writable); + } + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::ReadWrite | QIODevice::Unbuffered), writable); + } +} +#endif + +void tst_QFile::caseSensitivity() +{ +#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WIN) || defined(Q_OS_MAC) + const bool caseSensitive = false; +#else + const bool caseSensitive = true; +#endif + QByteArray testData("a little test"); + QString filename("File.txt"); + { + QFile f(filename); + QVERIFY(f.open(QIODevice::WriteOnly)); + QVERIFY(f.write(testData)); + f.close(); + } + QStringList alternates; + QFileInfo fi(filename); + QVERIFY(fi.exists()); + alternates << "file.txt" << "File.TXT" << "fIlE.TxT" << fi.absoluteFilePath().toUpper() << fi.absoluteFilePath().toLower(); + foreach (QString alt, alternates) { + QFileInfo fi2(alt); + QCOMPARE(fi2.exists(), !caseSensitive); + QCOMPARE(fi.size() == fi2.size(), !caseSensitive); + QFile f2(alt); + QCOMPARE(f2.open(QIODevice::ReadOnly), !caseSensitive); + if (!caseSensitive) + QCOMPARE(f2.readAll(), testData); + } +} + QTEST_MAIN(tst_QFile) #include "tst_qfile.moc" diff --git a/tests/auto/qfiledialog/resources/file.txt b/tests/auto/qfiledialog/resources/file.txt new file mode 100644 index 0000000..8a03e0e --- /dev/null +++ b/tests/auto/qfiledialog/resources/file.txt @@ -0,0 +1 @@ +This is a simple text file. diff --git a/tests/auto/qfiledialog/tst_qfiledialog.cpp b/tests/auto/qfiledialog/tst_qfiledialog.cpp index ca7c445..668a3e0 100644 --- a/tests/auto/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/qfiledialog/tst_qfiledialog.cpp @@ -61,9 +61,13 @@ #include <qlineedit.h> #include <qlayout.h> #include "../../shared/util.h" +#if defined QT_BUILD_INTERNAL #include "../../../src/gui/dialogs/qsidebar_p.h" #include "../../../src/gui/dialogs/qfilesystemmodel_p.h" #include "../../../src/gui/dialogs/qfiledialog_p.h" +#endif +#include <QFileDialog> +#include <QFileSystemModel> #include "../network-settings.h" @@ -183,7 +187,7 @@ public: QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return QSize(); } }; -// emited any time the selection model emits current changed +// emitted any time the selection model emits current changed void tst_QFiledialog::currentChangedSignal() { QNonNativeFileDialog fd; @@ -208,7 +212,7 @@ void tst_QFiledialog::currentChangedSignal() QCOMPARE(spyCurrentChanged.count(), 1); } -// only emited from the views, sidebar, or lookin combo +// only emitted from the views, sidebar, or lookin combo void tst_QFiledialog::directoryEnteredSignal() { #if defined QT_BUILD_INTERNAL @@ -269,13 +273,13 @@ void tst_QFiledialog::filesSelectedSignal_data() QTest::newRow("existingFiles") << QFileDialog::ExistingFiles; } -// emited when the dialog closes with the selected files +// emitted when the dialog closes with the selected files void tst_QFiledialog::filesSelectedSignal() { QNonNativeFileDialog fd; fd.setViewMode(QFileDialog::List); fd.setOptions(QFileDialog::DontUseNativeDialog); - QDir testDir(SRCDIR"/../../.."); + QDir testDir(SRCDIR); fd.setDirectory(testDir); QFETCH(QFileDialog::FileMode, fileMode); fd.setFileMode(fileMode); @@ -313,7 +317,7 @@ void tst_QFiledialog::filesSelectedSignal() QCOMPARE(spyFilesSelected.count(), 1); } -// only emited when the combo box is activated +// only emitted when the combo box is activated void tst_QFiledialog::filterSelectedSignal() { QNonNativeFileDialog fd; @@ -1304,6 +1308,10 @@ QString saveName(QWidget *, const QString &, const QString &, const QString &, Q void tst_QFiledialog::hooks() { +#ifdef Q_OS_SYMBIAN + if(QSysInfo::symbianVersion() < QSysInfo::SV_SF_3) + QSKIP("writing to data exports in paged dll not supported and crashes on symbian versions prior to ^3", SkipAll); +#endif qt_filedialog_existing_directory_hook = &existing; qt_filedialog_save_filename_hook = &saveName; qt_filedialog_open_filename_hook = &openName; diff --git a/tests/auto/qfileinfo/qfileinfo.pro b/tests/auto/qfileinfo/qfileinfo.pro index 3141db6..b35b1e0 100644 --- a/tests/auto/qfileinfo/qfileinfo.pro +++ b/tests/auto/qfileinfo/qfileinfo.pro @@ -10,9 +10,11 @@ wince*:|symbian: { deploy.files += qfileinfo.qrc tst_qfileinfo.cpp res.files = resources\\file1 resources\\file1.ext1 resources\\file1.ext1.ext2 res.path = resources - DEPLOYMENT = deploy res + DEPLOYMENT += deploy res } +win32*:LIBS += -ladvapi32 -lnetapi32 + symbian { TARGET.CAPABILITY=AllFiles LIBS *= -lefsrv @@ -28,3 +30,6 @@ wince* { DEFINES += SRCDIR=\\\"$$PWD/\\\" } +contains(QT_CONFIG, qt3support): QT += qt3support + +CONFIG += parallel_test diff --git a/tests/auto/qfileinfo/tst_qfileinfo.cpp b/tests/auto/qfileinfo/tst_qfileinfo.cpp index 202f212..2e1ab39 100644 --- a/tests/auto/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/qfileinfo/tst_qfileinfo.cpp @@ -59,6 +59,7 @@ #define _WIN32_WINNT 0x500 #include <qt_windows.h> #include <qlibrary.h> +#include <lm.h> #endif #include <qplatformdefs.h> #include <qdebug.h> @@ -72,6 +73,7 @@ #if defined(Q_OS_SYMBIAN) # define SRCDIR "" +# define NO_SYMLINKS #endif QT_BEGIN_NAMESPACE @@ -187,6 +189,11 @@ private slots: void notEqualOperator() const; void detachingOperations(); + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + void owner(); +#endif + void group(); }; tst_QFileInfo::tst_QFileInfo() @@ -415,6 +422,7 @@ void tst_QFileInfo::exists_data() QTest::newRow("data9") << SRCDIR "resources/file?.ext1" << false; QTest::newRow("data10") << "." << true; QTest::newRow("data11") << ". " << false; + QTest::newRow("empty") << "" << false; QTest::newRow("simple dir") << SRCDIR "resources" << true; QTest::newRow("simple dir with slash") << SRCDIR "resources/" << true; @@ -517,7 +525,11 @@ void tst_QFileInfo::absFilePath() QFETCH(QString, expected); QFileInfo fi(file); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QVERIFY(QString::compare(fi.absoluteFilePath(), expected, Qt::CaseInsensitive) == 0); +#else QCOMPARE(fi.absoluteFilePath(), expected); +#endif } void tst_QFileInfo::canonicalPath() @@ -607,20 +619,29 @@ void tst_QFileInfo::canonicalFilePath() #ifdef Q_OS_WIN typedef BOOL (WINAPI *PtrCreateSymbolicLink)(LPTSTR, LPTSTR, DWORD); PtrCreateSymbolicLink ptrCreateSymbolicLink = - (PtrCreateSymbolicLink)QLibrary::resolve(QLatin1String("kernel32"), "CreateSymbolicLink"); + (PtrCreateSymbolicLink)QLibrary::resolve(QLatin1String("kernel32"), "CreateSymbolicLinkW"); - if (!ptrCreateSymbolicLink || - ptrCreateSymbolicLink((wchar_t*)QString("res").utf16(), (wchar_t*)QString("resources").utf16(), 1) == 0) { + if (!ptrCreateSymbolicLink) { QSKIP("Symbolic links aren't supported by FS", SkipAll); + } else { + // CreateSymbolicLink can return TRUE & still fail to create the link, + // the error code in that case is ERROR_PRIVILEGE_NOT_HELD (1314) + SetLastError(0); + BOOL ret = ptrCreateSymbolicLink((wchar_t*)QString("res").utf16(), (wchar_t*)QString("resources").utf16(), 1); + DWORD dwErr = GetLastError(); + if (!ret) + QSKIP("Symbolic links aren't supported by FS", SkipAll); + QString currentPath = QDir::currentPath(); + bool is_res_Current = QDir::setCurrent("res"); + if (!is_res_Current && dwErr == 1314) + QSKIP("Not enough privilages to create Symbolic links", SkipAll); + QCOMPARE(is_res_Current, true); + + QCOMPARE(QFileInfo("file1").canonicalFilePath(), currentPath + "/resources/file1"); + + QCOMPARE(QDir::setCurrent(currentPath), true); + QDir::current().rmdir("res"); } - - QString currentPath = QDir::currentPath(); - QCOMPARE(QDir::setCurrent("res"), true); - - QCOMPARE(QFileInfo("file1").canonicalFilePath(), currentPath + "/resources/file1"); - - QCOMPARE(QDir::setCurrent(currentPath), true); - QFile::remove("res"); #endif } @@ -698,10 +719,19 @@ void tst_QFileInfo::dir() QFETCH(QString, expected); QFileInfo fi(file); - if (absPath) + if (absPath) { QCOMPARE(fi.absolutePath(), expected); - else + QCOMPARE(fi.absoluteDir().path(), expected); +#ifdef QT3_SUPPORT + QCOMPARE(fi.dir(true).path(), expected); +#endif + } else { QCOMPARE(fi.path(), expected); + QCOMPARE(fi.dir().path(), expected); +#ifdef QT3_SUPPORT + QCOMPARE(fi.dir(false).path(), expected); +#endif + } } @@ -1089,6 +1119,7 @@ void tst_QFileInfo::fileTimes_oldFile() void tst_QFileInfo::isSymLink_data() { +#ifndef NO_SYMLINKS QFile::remove("link.lnk"); QFile::remove("brokenlink.lnk"); QFile::remove("dummyfile"); @@ -1108,10 +1139,12 @@ void tst_QFileInfo::isSymLink_data() QTest::newRow("existent file") << SRCDIR "tst_qfileinfo.cpp" << false << ""; QTest::newRow("link") << "link.lnk" << true << QFileInfo(SRCDIR "tst_qfileinfo.cpp").absoluteFilePath(); QTest::newRow("broken link") << "brokenlink.lnk" << true << QFileInfo("dummyfile").absoluteFilePath(); +#endif } void tst_QFileInfo::isSymLink() { +#ifndef NO_SYMLINKS QFETCH(QString, path); QFETCH(bool, isSymLink); QFETCH(QString, linkTarget); @@ -1119,6 +1152,9 @@ void tst_QFileInfo::isSymLink() QFileInfo fi(path); QCOMPARE(fi.isSymLink(), isSymLink); QCOMPARE(fi.symLinkTarget(), linkTarget); +#else + QSKIP("no symbolic link support on this platform", SkipAll); +#endif } void tst_QFileInfo::isHidden_data() @@ -1252,9 +1288,10 @@ void tst_QFileInfo::isLocalFs() QFileInfo info(path); QFileInfoPrivate *privateInfo = getPrivate(info); - QVERIFY(privateInfo->fileEngine); - QCOMPARE(bool(privateInfo->fileEngine->fileFlags(QAbstractFileEngine::LocalDiskFlag) - & QAbstractFileEngine::LocalDiskFlag), isLocalFs); + QCOMPARE((privateInfo->fileEngine == 0), isLocalFs); + if (privateInfo->fileEngine) + QCOMPARE(bool(privateInfo->fileEngine->fileFlags(QAbstractFileEngine::LocalDiskFlag) + & QAbstractFileEngine::LocalDiskFlag), isLocalFs); } void tst_QFileInfo::refresh() @@ -1343,8 +1380,24 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() file.open(QIODevice::ReadWrite); file.close(); - QVERIFY(pwd.exists("abs_symlink") || createSymbolicLinkW((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x1)); - QVERIFY(pwd.exists(relSymlink) || createSymbolicLinkW((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x1)); + DWORD err = ERROR_SUCCESS ; + if (!pwd.exists("abs_symlink")) + if (!createSymbolicLinkW((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x1)) + err = GetLastError(); + if (err == ERROR_SUCCESS && !pwd.exists(relSymlink)) + if (!createSymbolicLinkW((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x1)) + err = GetLastError(); + if (err != ERROR_SUCCESS) { + wchar_t errstr[0x100]; + DWORD count = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, + 0, err, 0, errstr, 0x100, 0); + QString error(QString::fromUtf16(errstr, count)); + qWarning() << error; + //we need at least one data set for the test not to assert fail when skipping _data function + QDir target("target"); + QTest::newRow("dummy") << target.path() << false << "" << target.canonicalPath(); + QSKIP("link not supported by FS or insufficient privilege", SkipSingle); + } QVERIFY(file.exists()); QTest::newRow("absolute dir symlink") << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalPath(); @@ -1433,10 +1486,6 @@ void tst_QFileInfo::brokenShortcut() void tst_QFileInfo::isWritable() { -#ifdef Q_OS_SYMBIAN - QSKIP("Currently skipped on Symbian OS, but surely there is a writeable file somewhere???", SkipAll); -#endif - QFile tempfile("tempfile.txt"); tempfile.open(QIODevice::WriteOnly); tempfile.write("This file is generated by the QFileInfo autotest."); @@ -1454,7 +1503,7 @@ void tst_QFileInfo::isWritable() QVERIFY(fi.exists()); QVERIFY(!fi.isWritable()); #endif -#ifdef Q_OS_UNIX +#if defined (Q_OS_UNIX) && !defined (Q_OS_SYMBIAN) if (::getuid() == 0) QVERIFY(QFileInfo("/etc/passwd").isWritable()); else @@ -1465,9 +1514,6 @@ void tst_QFileInfo::isWritable() void tst_QFileInfo::isExecutable() { #ifdef Q_OS_SYMBIAN -# if defined(Q_CC_NOKIAX86) - QSKIP("Impossible to implement reading/touching of application binaries in Symbian emulator", SkipAll); -# endif QString appPath = "c:/sys/bin/tst_qfileinfo.exe"; #else QString appPath = QCoreApplication::applicationDirPath(); @@ -1601,5 +1647,115 @@ void tst_QFileInfo::detachingOperations() QVERIFY(!info1.caching()); } +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) +#if defined (Q_OS_WIN) +BOOL IsUserAdmin() +{ + BOOL b; + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + PSID AdministratorsGroup; + b = AllocateAndInitializeSid( + &NtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &AdministratorsGroup); + if (b) { + if (!CheckTokenMembership( NULL, AdministratorsGroup, &b)) + b = FALSE; + FreeSid(AdministratorsGroup); + } + + return(b); +} +#endif + +void tst_QFileInfo::owner() +{ + QString userName; +#if defined(Q_OS_UNIX) + char *usernameBuf = getlogin(); + if (usernameBuf) { + userName = QString::fromLocal8Bit(usernameBuf); + } +#endif +#if defined(Q_OS_WIN) + wchar_t usernameBuf[1024]; + DWORD bufSize = 1024; + if (GetUserNameW(usernameBuf, &bufSize)) { + userName = QString::fromWCharArray(usernameBuf); + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && IsUserAdmin()) { + // Special case : If the user is a member of Administrators group, all files + // created by the current user are owned by the Administrators group. + LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; + DWORD dwLevel = 0; + DWORD dwFlags = LG_INCLUDE_INDIRECT ; + DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; + DWORD dwEntriesRead = 0; + DWORD dwTotalEntries = 0; + NET_API_STATUS nStatus; + nStatus = NetUserGetLocalGroups(0, usernameBuf, dwLevel, dwFlags, (LPBYTE *) &pBuf, + dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries); + // Check if the current user is a member of Administrators group + if (nStatus == NERR_Success && pBuf){ + for (int i = 0; i < dwEntriesRead; i++) { + QString groupName = QString::fromWCharArray(pBuf[i].lgrui0_name); + if (!groupName.compare(QLatin1String("Administrators"))) + userName = groupName; + } + } + if (pBuf != NULL) + NetApiBufferFree(pBuf); + } + } + extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; + qt_ntfs_permission_lookup = 1; +#endif + if (userName.isEmpty()) + QSKIP("Can't retrieve the user name", SkipAll); + QString fileName("ownertest.txt"); + if (QFile::exists(fileName)) + QFile::remove(fileName); + QFile testFile(fileName); + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text)); + QByteArray testData("testfile"); + QVERIFY(testFile.write(testData) != -1); + testFile.close(); + QFileInfo fi(fileName); + QVERIFY(fi.exists()); + QCOMPARE(userName, fi.owner()); + if (QFile::exists(fileName)) + QFile::remove(fileName); +#if defined(Q_OS_WIN) + qt_ntfs_permission_lookup = 0; +#endif +} +#endif + +void tst_QFileInfo::group() +{ + QString expected; +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + struct group *gr; + gid_t gid = getegid(); + gr = getgrgid(gid); + expected = QString::fromLocal8Bit(gr->gr_name); +#endif + + QString fileName("ownertest.txt"); + if (QFile::exists(fileName)) + QFile::remove(fileName); + QFile testFile(fileName); + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text)); + QByteArray testData("testfile"); + QVERIFY(testFile.write(testData) != -1); + testFile.close(); + QFileInfo fi(fileName); + QVERIFY(fi.exists()); + + QCOMPARE(fi.group(), expected); +} + QTEST_MAIN(tst_QFileInfo) #include "tst_qfileinfo.moc" diff --git a/tests/auto/qfilesystementry/qfilesystementry.pro b/tests/auto/qfilesystementry/qfilesystementry.pro new file mode 100644 index 0000000..b9b43e6 --- /dev/null +++ b/tests/auto/qfilesystementry/qfilesystementry.pro @@ -0,0 +1,8 @@ +load(qttest_p4) + +SOURCES += tst_qfilesystementry.cpp \ + ../../../src/corelib/io/qfilesystementry.cpp +HEADERS += ../../../src/corelib/io/qfilesystementry_p.h +QT = core + +CONFIG += parallel_test diff --git a/tests/auto/qfilesystementry/tst_qfilesystementry.cpp b/tests/auto/qfilesystementry/tst_qfilesystementry.cpp new file mode 100644 index 0000000..4375f99 --- /dev/null +++ b/tests/auto/qfilesystementry/tst_qfilesystementry.cpp @@ -0,0 +1,387 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtTest/QtTest> + +#include <QtCore/private/qfilesystementry_p.h> + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +# define WIN_STUFF +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QFileSystemEntry : public QObject +{ + Q_OBJECT + +private slots: + void getSetCheck_data(); + void getSetCheck(); + void suffix_data(); + void suffix(); + void completeSuffix_data(); + void completeSuffix(); + void baseName_data(); + void baseName(); + void completeBaseName_data(); + void completeBaseName(); +#if defined(WIN_STUFF) + void absoluteOrRelative_data(); + void absoluteOrRelative(); +#endif +}; + +#if defined(WIN_STUFF) +void tst_QFileSystemEntry::getSetCheck_data() +{ + QTest::addColumn<QString>("nativeFilePath"); + QTest::addColumn<QString>("internalnativeFilePath"); + QTest::addColumn<QString>("filepath"); + QTest::addColumn<QString>("filename"); + QTest::addColumn<QString>("baseName"); + QTest::addColumn<QString>("completeBasename"); + QTest::addColumn<QString>("suffix"); + QTest::addColumn<QString>("completeSuffix"); + QTest::addColumn<bool>("absolute"); + QTest::addColumn<bool>("relative"); + + QString absPrefix = QLatin1String("\\\\?\\"); + QString relPrefix = absPrefix + + QDir::toNativeSeparators(QDir::currentPath()) + + QLatin1String("\\"); + + QTest::newRow("simple") + << QString("A:\\home\\qt\\in\\a\\dir.tar.gz") + << absPrefix + QString("A:\\home\\qt\\in\\a\\dir.tar.gz") + << "A:/home/qt/in/a/dir.tar.gz" + << "dir.tar.gz" << "dir" << "dir.tar" << "gz" << "tar.gz" << true << false; + + QTest::newRow("relative") + << QString("in\\a\\dir.tar.gz") + << relPrefix + QString("in\\a\\dir.tar.gz") + << "in/a/dir.tar.gz" + << "dir.tar.gz" << "dir" << "dir.tar" << "gz" << "tar.gz" << false <<true; + + QTest::newRow("noSuffix") + << QString("myDir\\myfile") + << relPrefix + QString("myDir\\myfile") + << "myDir/myfile" << "myfile" << "myfile" << "myfile" << "" << "" << false <<true; + + QTest::newRow("noLongSuffix") + << QString("myDir\\myfile.txt") + << relPrefix + QString("myDir\\myfile.txt") + << "myDir/myfile.txt" << "myfile.txt" << "myfile" << "myfile" << "txt" << "txt" << false << true; + + QTest::newRow("endingSlash") + << QString("myDir\\myfile.bla\\") + << relPrefix + QString("myDir\\myfile.bla\\") + << "myDir/myfile.bla/" << "" << "" << "" << "" << "" << false << true; + + QTest::newRow("absolutePath") + << QString("A:dir\\without\\leading\\backslash.bat") + << absPrefix + QString("A:\\dir\\without\\leading\\backslash.bat") + << "A:dir/without/leading/backslash.bat" << "backslash.bat" << "backslash" << "backslash" << "bat" << "bat" << false << false; +} + +void tst_QFileSystemEntry::getSetCheck() +{ + QFETCH(QString, nativeFilePath); + QFETCH(QString, internalnativeFilePath); + QFETCH(QString, filepath); + QFETCH(QString, filename); + QFETCH(QString, baseName); + QFETCH(QString, completeBasename); + QFETCH(QString, suffix); + QFETCH(QString, completeSuffix); + QFETCH(bool, absolute); + QFETCH(bool, relative); + + QFileSystemEntry entry1(filepath); + QCOMPARE(entry1.filePath(), filepath); + QCOMPARE(entry1.nativeFilePath().toLower(), internalnativeFilePath.toLower()); + QCOMPARE(entry1.fileName(), filename); + QCOMPARE(entry1.suffix(), suffix); + QCOMPARE(entry1.completeSuffix(), completeSuffix); + QCOMPARE(entry1.isAbsolute(), absolute); + QCOMPARE(entry1.isRelative(), relative); + QCOMPARE(entry1.baseName(), baseName); + QCOMPARE(entry1.completeBaseName(), completeBasename); + + QFileSystemEntry entry2(nativeFilePath, QFileSystemEntry::FromNativePath()); + QCOMPARE(entry2.suffix(), suffix); + QCOMPARE(entry2.completeSuffix(), completeSuffix); + QCOMPARE(entry2.isAbsolute(), absolute); + QCOMPARE(entry2.isRelative(), relative); + QCOMPARE(entry2.filePath(), filepath); + // Since this entry was created using the native path, + // the object shouldnot change nativeFilePath. + QCOMPARE(entry2.nativeFilePath(), nativeFilePath); + QCOMPARE(entry2.fileName(), filename); + QCOMPARE(entry2.baseName(), baseName); + QCOMPARE(entry2.completeBaseName(), completeBasename); +} + +#else + +void tst_QFileSystemEntry::getSetCheck_data() +{ + QTest::addColumn<QByteArray>("nativeFilePath"); + QTest::addColumn<QString>("filepath"); + QTest::addColumn<QString>("filename"); + QTest::addColumn<QString>("basename"); + QTest::addColumn<QString>("completeBasename"); + QTest::addColumn<QString>("suffix"); + QTest::addColumn<QString>("completeSuffix"); + QTest::addColumn<bool>("absolute"); + + QTest::newRow("simple") + << QByteArray("/home/qt/in/a/dir.tar.gz") + << "/home/qt/in/a/dir.tar.gz" + << "dir.tar.gz" << "dir" << "dir.tar" << "gz" << "tar.gz" << true; + QTest::newRow("relative") + << QByteArray("in/a/dir.tar.gz") + << "in/a/dir.tar.gz" + << "dir.tar.gz" << "dir" << "dir.tar" << "gz" << "tar.gz" << false; + + QTest::newRow("noSuffix") + << QByteArray("myDir/myfile") + << "myDir/myfile" << "myfile" << "myfile" << "myfile" << "" << "" << false; + + QTest::newRow("noLongSuffix") + << QByteArray("myDir/myfile.txt") + << "myDir/myfile.txt" << "myfile.txt" << "myfile" << "myfile" << "txt" << "txt" << false; + + QTest::newRow("endingSlash") + << QByteArray("myDir/myfile.bla/") + << "myDir/myfile.bla/" << "" << "" << "" << "" << "" << false; + + QTest::newRow("relativePath") + << QByteArray("A:dir/without/leading/backslash.bat") + << "A:dir/without/leading/backslash.bat" << "backslash.bat" << "backslash" << "backslash" << "bat" << "bat" << false; +} + +void tst_QFileSystemEntry::getSetCheck() +{ + QFETCH(QByteArray, nativeFilePath); + QFETCH(QString, filepath); + QFETCH(QString, filename); + QFETCH(QString, basename); + QFETCH(QString, completeBasename); + QFETCH(QString, suffix); + QFETCH(QString, completeSuffix); + QFETCH(bool, absolute); + + QFileSystemEntry entry1(filepath); + QCOMPARE(entry1.filePath(), filepath); + QCOMPARE(entry1.nativeFilePath(), nativeFilePath); + QCOMPARE(entry1.fileName(), filename); + QCOMPARE(entry1.suffix(), suffix); + QCOMPARE(entry1.completeSuffix(), completeSuffix); + QCOMPARE(entry1.isAbsolute(), absolute); + QCOMPARE(entry1.isRelative(), !absolute); + QCOMPARE(entry1.baseName(), basename); + QCOMPARE(entry1.completeBaseName(), completeBasename); + + QFileSystemEntry entry2(nativeFilePath, QFileSystemEntry::FromNativePath()); + QCOMPARE(entry2.suffix(), suffix); + QCOMPARE(entry2.completeSuffix(), completeSuffix); + QCOMPARE(entry2.isAbsolute(), absolute); + QCOMPARE(entry2.isRelative(), !absolute); + QCOMPARE(entry2.filePath(), filepath); + QCOMPARE(entry2.nativeFilePath(), nativeFilePath); + QCOMPARE(entry2.fileName(), filename); + QCOMPARE(entry2.baseName(), basename); + QCOMPARE(entry2.completeBaseName(), completeBasename); +} +#endif + +void tst_QFileSystemEntry::suffix_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("noextension0") << "file" << ""; + QTest::newRow("noextension1") << "/path/to/file" << ""; + QTest::newRow("data0") << "file.tar" << "tar"; + QTest::newRow("data1") << "file.tar.gz" << "gz"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "gz"; + QTest::newRow("data3") << "/path/file.tar" << "tar"; + QTest::newRow("hidden1") << ".ext1" << "ext1"; + QTest::newRow("hidden1") << ".ext" << "ext"; + QTest::newRow("hidden1") << ".ex" << "ex"; + QTest::newRow("hidden1") << ".e" << "e"; + QTest::newRow("hidden2") << ".ext1.ext2" << "ext2"; + QTest::newRow("hidden2") << ".ext.ext2" << "ext2"; + QTest::newRow("hidden2") << ".ex.ext2" << "ext2"; + QTest::newRow("hidden2") << ".e.ext2" << "ext2"; + QTest::newRow("hidden2") << "..ext2" << "ext2"; + QTest::newRow("dots") << "/path/file.with.dots/file..ext2" << "ext2"; + QTest::newRow("dots2") << "/path/file.with.dots/.file..ext2" << "ext2"; +} + +void tst_QFileSystemEntry::suffix() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileSystemEntry fe(file); + QCOMPARE(fe.suffix(), expected); + + QFileSystemEntry fi2(file); + // first resolve the last slash + (void) fi2.path(); + QCOMPARE(fi2.suffix(), expected); +} + +void tst_QFileSystemEntry::completeSuffix_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("noextension0") << "file" << ""; + QTest::newRow("noextension1") << "/path/to/file" << ""; + QTest::newRow("data0") << "file.tar" << "tar"; + QTest::newRow("data1") << "file.tar.gz" << "tar.gz"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "tar.gz"; + QTest::newRow("data3") << "/path/file.tar" << "tar"; + QTest::newRow("dots") << "/path/file.with.dots/file..ext2" << ".ext2"; + QTest::newRow("dots2") << "/path/file.with.dots/.file..ext2" << "file..ext2"; +} + +void tst_QFileSystemEntry::completeSuffix() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileSystemEntry fi(file); + QCOMPARE(fi.completeSuffix(), expected); + + QFileSystemEntry fi2(file); + // first resolve the last slash + (void) fi2.path(); + QCOMPARE(fi2.completeSuffix(), expected); +} + +void tst_QFileSystemEntry::baseName_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("data0") << "file.tar" << "file"; + QTest::newRow("data1") << "file.tar.gz" << "file"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "file"; + QTest::newRow("data3") << "/path/file.tar" << "file"; + QTest::newRow("data4") << "/path/file" << "file"; + QTest::newRow("dots") << "/path/file.with.dots/file..ext2" << "file"; + QTest::newRow("dots2") << "/path/file.with.dots/.file..ext2" << ""; +} + +void tst_QFileSystemEntry::baseName() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileSystemEntry fi(file); + QCOMPARE(fi.baseName(), expected); + + QFileSystemEntry fi2(file); + // first resolve the last slash + (void) fi2.path(); + QCOMPARE(fi2.baseName(), expected); +} + +void tst_QFileSystemEntry::completeBaseName_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("data0") << "file.tar" << "file"; + QTest::newRow("data1") << "file.tar.gz" << "file.tar"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "file.tar"; + QTest::newRow("data3") << "/path/file.tar" << "file"; + QTest::newRow("data4") << "/path/file" << "file"; + QTest::newRow("dots") << "/path/file.with.dots/file..ext2" << "file."; + QTest::newRow("dots2") << "/path/file.with.dots/.file..ext2" << ".file."; +} + +void tst_QFileSystemEntry::completeBaseName() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileSystemEntry fi(file); + QCOMPARE(fi.completeBaseName(), expected); + + QFileSystemEntry fi2(file); + // first resolve the last slash + (void) fi2.path(); + QCOMPARE(fi2.completeBaseName(), expected); +} + +#if defined(WIN_STUFF) +void tst_QFileSystemEntry::absoluteOrRelative_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isAbsolute"); + QTest::addColumn<bool>("isRelative"); + + QTest::newRow("data0") << "file.tar" << false << true; + QTest::newRow("data1") << "/path/file/file.tar.gz" << false << false; + QTest::newRow("data1") << "C:path/file/file.tar.gz" << false << false; + QTest::newRow("data3") << "C:/path/file" << true << false; + QTest::newRow("data3") << "//machine/share" << true << false; +} + +void tst_QFileSystemEntry::absoluteOrRelative() +{ + QFETCH(QString, path); + QFETCH(bool, isAbsolute); + QFETCH(bool, isRelative); + + QFileSystemEntry fi(path); + QCOMPARE(fi.isAbsolute(), isAbsolute); + QCOMPARE(fi.isRelative(), isRelative); +} +#endif + +QTEST_MAIN(tst_QFileSystemEntry) +#include <tst_qfilesystementry.moc> diff --git a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp index c234c96..6b63691 100644 --- a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -41,7 +41,10 @@ #include <QtTest/QtTest> +#ifdef QT_BUILD_INTERNAL #include "../../../src/gui/dialogs/qfilesystemmodel_p.h" +#endif +#include <QFileSystemModel> #include <QFileIconProvider> #include <QTreeView> #include <QHeaderView> @@ -826,8 +829,10 @@ void tst_QFileSystemModel::sort() MyFriendFileSystemModel *myModel = new MyFriendFileSystemModel(); QTreeView *tree = new QTreeView(); +#ifdef QT_BUILD_INTERNAL if (fileDialogMode) myModel->d_func()->disableRecursiveSort = true; +#endif QDir dir(QDir::tempPath()); //initialize the randomness @@ -992,8 +997,8 @@ void tst_QFileSystemModel::dirsBeforeFiles() } dir.rmdir(dirPath); } - dir.mkpath(dirPath); - QVERIFY(dir.exists()); + QVERIFY(dir.mkpath(dirPath)); + QVERIFY(QDir(dirPath).exists()); for (int i = 0; i < 3; ++i) { QLatin1Char c('a' + i); diff --git a/tests/auto/qfilesystemwatcher/qfilesystemwatcher.pro b/tests/auto/qfilesystemwatcher/qfilesystemwatcher.pro index 8b8616a..75e85a0 100644 --- a/tests/auto/qfilesystemwatcher/qfilesystemwatcher.pro +++ b/tests/auto/qfilesystemwatcher/qfilesystemwatcher.pro @@ -1,3 +1,5 @@ load(qttest_p4) SOURCES += tst_qfilesystemwatcher.cpp QT = core + +CONFIG += parallel_test diff --git a/tests/auto/qhttp/qhttp.pro b/tests/auto/qhttp/qhttp.pro index 5b102ce..49eebd5 100644 --- a/tests/auto/qhttp/qhttp.pro +++ b/tests/auto/qhttp/qhttp.pro @@ -11,7 +11,7 @@ wince*: { cgi.path = webserver/cgi-bin addFiles.files = rfc3252.txt trolltech addFiles.path = . - DEPLOYMENT = addFiles webFiles cgi + DEPLOYMENT += addFiles webFiles cgi DEFINES += SRCDIR=\\\"\\\" } else:symbian { webFiles.files = webserver/* @@ -20,7 +20,7 @@ wince*: { cgi.path = webserver/cgi-bin addFiles.files = rfc3252.txt trolltech addFiles.path = . - DEPLOYMENT = addFiles webFiles cgi + DEPLOYMENT += addFiles webFiles cgi TARGET.CAPABILITY = NetworkServices } else:vxworks*: { DEFINES += SRCDIR=\\\"\\\" diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index 4aff8d5..5742a97 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -1107,6 +1107,11 @@ void tst_QImageReader::readFromDevice() QCOMPARE(image1, expectedImage); } +#if defined (Q_OS_SYMBIAN) && defined (__WINS__) + //the emulator hangs in socket write (this is a test bug, it assumes the TCP stack can accept a whole image to its buffers) + if(imageData.size() > 16384) + QSKIP("image larger than socket buffer (test needs to be rewritten)", SkipSingle); +#endif Server server(imageData); QEventLoop loop; connect(&server, SIGNAL(ready()), &loop, SLOT(quit())); @@ -1258,7 +1263,10 @@ void tst_QImageReader::devicePosition() buf.seek(preLen); QImageReader reader(&buf, format); QCOMPARE(expected, reader.read()); - if (format != "ppm" && format != "gif") // Known not to work + if (format != "ppm" && + format != "pgm" && + format != "pbm" && + format != "gif") // Known not to work QCOMPARE(buf.pos(), qint64(preLen+imageDataSize)); } diff --git a/tests/auto/qlocalsocket/test/test.pro b/tests/auto/qlocalsocket/test/test.pro index f91fe58..b2755b5 100644 --- a/tests/auto/qlocalsocket/test/test.pro +++ b/tests/auto/qlocalsocket/test/test.pro @@ -42,7 +42,7 @@ symbian { wince*|symbian { scriptFiles.files = ../lackey/scripts/*.js scriptFiles.path = lackey/scripts - DEPLOYMENT = additionalFiles scriptFiles + DEPLOYMENT += additionalFiles scriptFiles QT += script # for easy deployment of QtScript requires(contains(QT_CONFIG,script)) diff --git a/tests/auto/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp index fd310f4..a497b13 100644 --- a/tests/auto/qprocess/tst_qprocess.cpp +++ b/tests/auto/qprocess/tst_qprocess.cpp @@ -1585,6 +1585,7 @@ void tst_QProcess::spaceArgsTest() #if defined(Q_OS_SYMBIAN) // Symbian test outputs to a file, so check that FILE* file = fopen("c:\\logs\\qprocess_args_test.txt","r"); + QVERIFY(file); char buf[256]; fgets(buf, 256, file); fclose(file); @@ -1614,6 +1615,7 @@ void tst_QProcess::spaceArgsTest() #if defined(Q_OS_SYMBIAN) // Symbian test outputs to a file, so check that file = fopen("c:\\logs\\qprocess_args_test.txt","r"); + QVERIFY(file); fgets(buf, 256, file); fclose(file); actual = QString::fromLatin1(buf).split("|"); @@ -1661,6 +1663,7 @@ void tst_QProcess::nativeArguments() # else FILE* file = fopen("\\temp\\qprocess_args_test.txt","r"); # endif + QVERIFY(file); char buf[256]; fgets(buf, 256, file); fclose(file); @@ -2285,7 +2288,9 @@ void tst_QProcess::detachedWorkingDirectoryAndPid() QFileInfo fi(infoFile); fi.setCaching(false); - while (fi.size() == 0) { + //The guard counter ensures the test does not hang if the sub process fails. + //Instead, the test will fail when trying to open & verify the sub process output file. + for (int guard = 0; guard < 100 && fi.size() == 0; guard++) { QTest::qSleep(100); } @@ -2397,6 +2402,7 @@ void tst_QProcess::startFinishStartFinish() #if defined(Q_OS_SYMBIAN) // Symbian test outputs to a file, so check that FILE* file = fopen("c:\\logs\\qprocess_output_test.txt","r"); + QVERIFY(file); char buf[30]; fgets(buf, 30, file); QCOMPARE(QString::fromLatin1(buf), diff --git a/tests/auto/qresourceengine/qresourceengine.pro b/tests/auto/qresourceengine/qresourceengine.pro index c0db52f..9ca6994 100644 --- a/tests/auto/qresourceengine/qresourceengine.pro +++ b/tests/auto/qresourceengine/qresourceengine.pro @@ -38,7 +38,7 @@ wince*|symbian:{ testsub.path = testqrc/test testsub2.files = testqrc/test/test/* testsub2.path = testqrc/test/test - DEPLOYMENT = deploy test alias other search1 search2 sub testsub testsub2 + DEPLOYMENT += deploy test alias other search1 search2 sub testsub testsub2 !symbian:DEFINES += SRCDIR=\\\"\\\" } else { DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/qsettings/qsettings.pro b/tests/auto/qsettings/qsettings.pro index 19513b3..fe104df 100644 --- a/tests/auto/qsettings/qsettings.pro +++ b/tests/auto/qsettings/qsettings.pro @@ -6,3 +6,5 @@ contains(QT_CONFIG, qt3support):QT += qt3support CONFIG -= debug CONFIG += release win32-msvc*:LIBS += advapi32.lib + +CONFIG += parallel_test diff --git a/tests/auto/qsound/qsound.pro b/tests/auto/qsound/qsound.pro index a1760f8..b69d084 100644 --- a/tests/auto/qsound/qsound.pro +++ b/tests/auto/qsound/qsound.pro @@ -3,7 +3,7 @@ SOURCES += tst_qsound.cpp wince*|symbian: { deploy.files += 4.wav - DEPLOYMENT = deploy + DEPLOYMENT += deploy !symbian:DEFINES += SRCDIR=\\\"\\\" } else { DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/qtemporaryfile/qtemporaryfile.pro b/tests/auto/qtemporaryfile/qtemporaryfile.pro index 543c143..64a043b 100644 --- a/tests/auto/qtemporaryfile/qtemporaryfile.pro +++ b/tests/auto/qtemporaryfile/qtemporaryfile.pro @@ -10,3 +10,5 @@ symbian { }else { DEFINES += SRCDIR=\\\"$$PWD/\\\" } + +CONFIG += parallel_test diff --git a/tests/auto/qxmlstream/qxmlstream.pro b/tests/auto/qxmlstream/qxmlstream.pro index 31d77e7..894801d 100644 --- a/tests/auto/qxmlstream/qxmlstream.pro +++ b/tests/auto/qxmlstream/qxmlstream.pro @@ -8,7 +8,7 @@ wince*|symbian: { addFiles.files = data XML-Test-Suite addFiles.path = . DEPLOYMENT += addFiles - DEFINES += SRCDIR=\\\"\\\" + wince*:DEFINES += SRCDIR=\\\"\\\" } else { DEFINES += SRCDIR=\\\"$$PWD/\\\" } diff --git a/tests/auto/qxmlstream/tst_qxmlstream.cpp b/tests/auto/qxmlstream/tst_qxmlstream.cpp index 7d5e3b7..19e4b90 100644 --- a/tests/auto/qxmlstream/tst_qxmlstream.cpp +++ b/tests/auto/qxmlstream/tst_qxmlstream.cpp @@ -55,6 +55,10 @@ //TESTED_CLASS=QXmlStreamReader QXmlStreamWriter //TESTED_FILES=corelib/xml/stream/qxmlutils.cpp corelib/xml/stream/qxmlstream.cpp corelib/xml/stream/qxmlstream_p.h +#ifdef Q_OS_SYMBIAN +#define SRCDIR "" +#endif + Q_DECLARE_METATYPE(QXmlStreamReader::ReadElementTextBehaviour) static const char *const catalogFile = SRCDIR "XML-Test-Suite/xmlconf/finalCatalog.xml"; diff --git a/tests/benchmarks/corelib/io/qdir/tree/bench_qdir_tree.cpp b/tests/benchmarks/corelib/io/qdir/tree/bench_qdir_tree.cpp index ad5ae98..84922f6 100644 --- a/tests/benchmarks/corelib/io/qdir/tree/bench_qdir_tree.cpp +++ b/tests/benchmarks/corelib/io/qdir/tree/bench_qdir_tree.cpp @@ -55,12 +55,24 @@ class bench_QDir_tree public: bench_QDir_tree() - : prefix("./test-tree/") + : prefix("./test-tree/"), + musicprefix(QLatin1String("music")), + photoprefix(QLatin1String("photos")), + sourceprefix(QLatin1String("source")), + musicsize(0), + photosize(0), + sourcesize(0) { } private: QByteArray prefix; + QString musicprefix; + QString photoprefix; + QString sourceprefix; + qint64 musicsize; + qint64 photosize; + qint64 sourcesize; private slots: void initTestCase() @@ -105,6 +117,34 @@ private slots: line.clear(); } + + //Use case: music collection - 10 files in 100 directories (albums) + QVERIFY(fs.createDirectory(musicprefix)); + for (int i=0;i<1000;i++) { + if ((i % 10) == 0) + QVERIFY(fs.createDirectory(QString("%1/directory%2").arg(musicprefix).arg(i/10))); + qint64 size = fs.createFileWithContent(QString("%1/directory%2/file%3").arg(musicprefix).arg(i/10).arg(i)); + QVERIFY(size > 0); + musicsize += size; + } + //Use case: photos - 1000 files in 1 directory + QVERIFY(fs.createDirectory(photoprefix)); + for (int i=0;i<1000;i++) { + qint64 size = fs.createFileWithContent(QString("%1/file%2").arg(photoprefix).arg(i)); + QVERIFY(size > 0); + photosize += size; + } + //Use case: source - 10 files in 10 subdirectories in 10 directories (1000 total) + QVERIFY(fs.createDirectory(sourceprefix)); + for (int i=0;i<1000;i++) { + if ((i % 100) == 0) + QVERIFY(fs.createDirectory(QString("%1/directory%2").arg(sourceprefix).arg(i/100))); + if ((i % 10) == 0) + QVERIFY(fs.createDirectory(QString("%1/directory%2/subdirectory%3").arg(sourceprefix).arg(i/100).arg(i/10))); + qint64 size = fs.createFileWithContent(QString("%1/directory%2/subdirectory%3/file%4").arg(sourceprefix).arg(i/100).arg(i/10).arg(i)); + QVERIFY(size > 0); + sourcesize += size; + } } void fileSearch_data() const @@ -154,6 +194,7 @@ private slots: QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); + count = 0; while (iterator.hasNext()) { iterator.next(); ++count; @@ -165,6 +206,32 @@ private slots: QCOMPARE(count, 11963); } + void thousandFiles_data() const + { + QTest::addColumn<QString>("dirName"); + QTest::addColumn<qint64>("expectedSize"); + QTest::newRow("music") << musicprefix << musicsize; + QTest::newRow("photos") << photoprefix << photosize; + QTest::newRow("src") << sourceprefix << sourcesize; + } + + void thousandFiles() const + { + QFETCH(QString, dirName); + QFETCH(qint64, expectedSize); + QBENCHMARK { + qint64 totalsize = 0; + int count = 0; + QDirIterator iter(dirName, QDir::Files, QDirIterator::Subdirectories); + while(iter.hasNext()) { + iter.next(); + count++; + totalsize += iter.fileInfo().size(); + } + QCOMPARE(count, 1000); + QCOMPARE(totalsize, expectedSize); + } + } private: FileSystem fs; }; diff --git a/tests/benchmarks/declarative/binding/binding.pro b/tests/benchmarks/declarative/binding/binding.pro index ceaabeb..bbe8701 100644 --- a/tests/benchmarks/declarative/binding/binding.pro +++ b/tests/benchmarks/declarative/binding/binding.pro @@ -10,7 +10,7 @@ HEADERS += testtypes.h symbian { data.files = data data.path = . - DEPLOYMENT = data + DEPLOYMENT += data } else { # Define SRCDIR equal to test's source directory DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/benchmarks/declarative/qdeclarativeimage/qdeclarativeimage.pro b/tests/benchmarks/declarative/qdeclarativeimage/qdeclarativeimage.pro index c4d5609..0d7c184 100644 --- a/tests/benchmarks/declarative/qdeclarativeimage/qdeclarativeimage.pro +++ b/tests/benchmarks/declarative/qdeclarativeimage/qdeclarativeimage.pro @@ -10,7 +10,7 @@ SOURCES += tst_qdeclarativeimage.cpp symbian { importFiles.files = image.png importFiles.path = - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/benchmarks/declarative/script/script.pro b/tests/benchmarks/declarative/script/script.pro index d6cb708..75faa5c 100644 --- a/tests/benchmarks/declarative/script/script.pro +++ b/tests/benchmarks/declarative/script/script.pro @@ -10,7 +10,7 @@ SOURCES += tst_script.cpp symbian { importFiles.files = data importFiles.path = - DEPLOYMENT = importFiles + DEPLOYMENT += importFiles } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } diff --git a/tests/shared/filesystem.h b/tests/shared/filesystem.h index 079a6dc..8274346 100644 --- a/tests/shared/filesystem.h +++ b/tests/shared/filesystem.h @@ -87,6 +87,16 @@ struct FileSystem return false; } + qint64 createFileWithContent(const QString &fileName) + { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) { + createdFiles << fileName; + return file.write(fileName.toUtf8()); + } + return -1; + } + bool createLink(const QString &destination, const QString &linkName) { if (QFile::link(destination, linkName)) { diff --git a/tools/configure/configure.pro b/tools/configure/configure.pro index 0a49fbe..608d876 100644 --- a/tools/configure/configure.pro +++ b/tools/configure/configure.pro @@ -48,6 +48,10 @@ HEADERS = configureapp.h environment.h tools.h\ $$QT_SOURCE_TREE/src/corelib/io/qdiriterator.h \ $$QT_SOURCE_TREE/src/corelib/io/qfile.h \ $$QT_SOURCE_TREE/src/corelib/io/qfileinfo.h \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystementry_p.h \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystemengine_p.h \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystemmetadata_p.h \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystemiterator_p.h \ $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine.h \ $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_iterator_p.h \ $$QT_SOURCE_TREE/src/corelib/io/qiodevice.h \ @@ -86,9 +90,13 @@ SOURCES = main.cpp configureapp.cpp environment.cpp tools.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qfile.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qfileinfo.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qabstractfileengine.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystementry.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystemengine.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystemengine_win.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystemiterator_win.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_win.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_iterator.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_iterator_win.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qiodevice.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qtextstream.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qtemporaryfile.cpp \ @@ -115,8 +123,6 @@ SOURCES = main.cpp configureapp.cpp environment.cpp tools.cpp \ $$QT_SOURCE_TREE/tools/shared/symbian/epocroot.cpp \ $$QT_SOURCE_TREE/tools/shared/windows/registry.cpp -win32:SOURCES += $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_win.cpp - DEFINES += COMMERCIAL_VERSION INCLUDEPATH += $$QT_SOURCE_TREE/src/corelib/arch/generic \ diff --git a/tools/qtestlib/wince/cetest/bootstrapped.pri b/tools/qtestlib/wince/cetest/bootstrapped.pri index b9c4b2b..56c8ab7 100644 --- a/tools/qtestlib/wince/cetest/bootstrapped.pri +++ b/tools/qtestlib/wince/cetest/bootstrapped.pri @@ -4,11 +4,14 @@ SOURCES += \ $$QT_SOURCE_TREE/src/corelib/tools/qstringlist.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qfile.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qdir.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystementry.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystemengine.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystemengine_win.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfilesystemiterator_win.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qabstractfileengine.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_win.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_iterator.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_iterator_win.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qfileinfo.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qtemporaryfile.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qdiriterator.cpp \ |