summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/io/qfsfileengine.cpp6
-rw-r--r--src/corelib/io/qfsfileengine_p.h10
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp56
-rw-r--r--src/corelib/kernel/qcore_symbian_p.h24
-rw-r--r--src/network/access/qnetworkaccessfilebackend.cpp5
-rw-r--r--tests/auto/qnetworkreply/tst_qnetworkreply.cpp7
6 files changed, 97 insertions, 11 deletions
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 0d23a27..548f9cf 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -120,7 +120,7 @@ void QFSFileEnginePrivate::init()
openMode = QIODevice::NotOpen;
fd = -1;
fh = 0;
-#ifdef Q_OS_SYMBIAN
+#if defined (Q_OS_SYMBIAN) && !defined(QT_SYMBIAN_USE_NATIVE_FILEMAP)
fileHandleForMaps = -1;
#endif
lastIOCommand = IOFlushCommand;
@@ -368,8 +368,10 @@ bool QFSFileEnginePrivate::closeFdFh()
if (fd == -1 && !fh
#ifdef Q_OS_SYMBIAN
&& !symbianFile.SubSessionHandle()
+#ifndef QT_SYMBIAN_USE_NATIVE_FILEMAP
&& fileHandleForMaps == -1
#endif
+#endif
)
return false;
@@ -378,7 +380,7 @@ bool QFSFileEnginePrivate::closeFdFh()
bool closed = true;
tried_stat = 0;
-#ifdef Q_OS_SYMBIAN
+#if defined(Q_OS_SYMBIAN) && !defined(QT_SYMBIAN_USE_NATIVE_FILEMAP)
// Map handle is always owned by us so always close it
if (fileHandleForMaps >= 0) {
QT_CLOSE(fileHandleForMaps);
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index 79dda1b..f93250e 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -62,6 +62,12 @@
#ifdef Q_OS_SYMBIAN
#include <f32file.h>
+//This macro will be defined if the OS supports memory mapped files
+#if defined (SYMBIAN_FILE_MAPPING_SUPPORTED) && !defined (WINS)
+//simpler define to check in sources
+#define QT_SYMBIAN_USE_NATIVE_FILEMAP
+#include <f32filemap.h>
+#endif
#endif
#ifndef QT_NO_FSFILEENGINE
@@ -139,9 +145,11 @@ public:
*/
TInt symbianFilePos;
#endif
+#ifndef QT_SYMBIAN_USE_NATIVE_FILEMAP
mutable int fileHandleForMaps;
int getMapHandle();
#endif
+#endif
#ifdef Q_WS_WIN
HANDLE fileHandle;
@@ -153,6 +161,8 @@ public:
#endif
mutable DWORD fileAttrib;
+#elif defined (QT_SYMBIAN_USE_NATIVE_FILEMAP)
+ QHash<uchar *, RFileMap> maps;
#else
QHash<uchar *, QPair<int /*offset % PageSize*/, size_t /*length + offset % PageSize*/> > maps;
#endif
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index 681e55d..9de282a 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -602,7 +602,7 @@ int QFSFileEnginePrivate::nativeHandle() const
return fh ? fileno(fh) : fd;
}
-#ifdef Q_OS_SYMBIAN
+#if defined(Q_OS_SYMBIAN) && !defined(QT_SYMBIAN_USE_NATIVE_FILEMAP)
int QFSFileEnginePrivate::getMapHandle()
{
if (symbianFile.SubSessionHandle()) {
@@ -925,6 +925,7 @@ QString QFSFileEngine::owner(FileOwner own) const
return QFileSystemEngine::resolveUserName(ownerId(own));
return QFileSystemEngine::resolveGroupName(ownerId(own));
#else
+ Q_UNUSED(own)
return QString();
#endif
}
@@ -1045,9 +1046,47 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
QT_OFF_T realOffset = QT_OFF_T(offset);
realOffset &= ~(QT_OFF_T(pageSize - 1));
+#ifdef QT_SYMBIAN_USE_NATIVE_FILEMAP
+ TInt nativeMapError = KErrNone;
+ RFileMap mapping;
+ TUint mode(EFileMapRemovableMedia);
+ //If the file was opened for write or read/write, then open the map for read/write
+ if (openMode & QIODevice::WriteOnly)
+ mode |= EFileMapWrite;
+ if (symbianFile.SubSessionHandle()) {
+ nativeMapError = mapping.Open(symbianFile, offset, size, mode);
+ } else {
+ //map file by name if we don't have a native handle
+ QString fn = QFileSystemEngine::absoluteName(fileEntry).nativeFilePath();
+ TUint filemode = EFileShareReadersOrWriters | EFileRead;
+ if (openMode & QIODevice::WriteOnly)
+ filemode |= EFileWrite;
+ nativeMapError = mapping.Open(qt_s60GetRFs(), qt_QString2TPtrC(fn), filemode, offset, size, mode);
+ }
+ if (nativeMapError == KErrNone) {
+ QScopedResource<RFileMap> ptr(mapping); //will call Close if adding to mapping throws an exception
+ uchar *address = mapping.Base();
+ maps[address] = mapping;
+ ptr.take();
+ return address;
+ }
+ QFile::FileError reportedError = QFile::UnspecifiedError;
+ switch (nativeMapError) {
+ case KErrAccessDenied:
+ case KErrPermissionDenied:
+ reportedError = QFile::PermissionsError;
+ break;
+ case KErrNoMemory:
+ reportedError = QFile::ResourceError;
+ break;
+ }
+ q->setError(reportedError, QSystemError(nativeMapError, QSystemError::NativeError).toString());
+ return 0;
+#else
#ifdef Q_OS_SYMBIAN
+ //older phones & emulator don't support native mapping, so need to keep the open C way around for those.
void *mapAddress;
- TRAPD(err, mapAddress = QT_MMAP((void*)0, realSize,
+ TRAPD(err, mapAddress = QT_MMAP((void*)0, realSize,
access, MAP_SHARED, getMapHandle(), realOffset));
if (err != KErrNone) {
qWarning("OpenC bug: leave from mmap %d", err);
@@ -1079,6 +1118,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
break;
}
return 0;
+#endif
}
bool QFSFileEnginePrivate::unmap(uchar *ptr)
@@ -1090,6 +1130,17 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
return false;
}
+#ifdef QT_SYMBIAN_USE_NATIVE_FILEMAP
+ RFileMap mapping = maps.value(ptr);
+ TInt err = mapping.Flush();
+ mapping.Close();
+ maps.remove(ptr);
+ if (err) {
+ q->setError(QFile::WriteError, QSystemError(err, QSystemError::NativeError).toString());
+ return false;
+ }
+ return true;
+#else
uchar *start = ptr - maps[ptr].first;
size_t len = maps[ptr].second;
if (-1 == munmap(start, len)) {
@@ -1098,6 +1149,7 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
}
maps.remove(ptr);
return true;
+#endif
#else
return false;
#endif
diff --git a/src/corelib/kernel/qcore_symbian_p.h b/src/corelib/kernel/qcore_symbian_p.h
index 3019e05..a8f576d 100644
--- a/src/corelib/kernel/qcore_symbian_p.h
+++ b/src/corelib/kernel/qcore_symbian_p.h
@@ -59,6 +59,7 @@
#include <qstring.h>
#include <qrect.h>
#include <qhash.h>
+#include <qscopedpointer.h>
#include <f32file.h>
#include <es_sock.h>
@@ -262,6 +263,29 @@ private:
RConnection *iDefaultConnection;
};
+template <typename T> class QScopedPointerResourceCloser
+{
+public:
+ static inline void cleanup(T* pointer)
+ {
+ if (pointer)
+ pointer->Close();
+ }
+};
+
+/*typical use:
+ RFile file;
+ file.Open(...);
+ QScopedResource<RFile> ptr(file);
+ container.append(file); //this may throw std::bad_alloc, in which case file.Close() is called by destructor
+ ptr.take(); //if we reach this line, ownership is transferred to the container
+ */
+template <typename T> class QScopedResource : public QScopedPointer<T, QScopedPointerResourceCloser<T> >
+{
+public:
+ inline QScopedResource(T& resource) : QScopedPointer<T, QScopedPointerResourceCloser<T> >(&resource) {}
+};
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp
index 42cc2c2..7c4adca 100644
--- a/src/network/access/qnetworkaccessfilebackend.cpp
+++ b/src/network/access/qnetworkaccessfilebackend.cpp
@@ -67,7 +67,7 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op,
QUrl url = request.url();
if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0 || url.isLocalFile()) {
return new QNetworkAccessFileBackend;
- } else if (!url.scheme().isEmpty() && url.authority().isEmpty()) {
+ } else if (!url.isEmpty() && url.authority().isEmpty()) {
// check if QFile could, in theory, open this URL via the file engines
// it has to be in the format:
// prefix:path/to/file
@@ -75,7 +75,8 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op,
//
// this construct here must match the one below in open()
QFileInfo fi(url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery));
- if ((url.scheme().length()==1) && fi.exists())
+ // On Windows and Symbian the drive letter is detected as the scheme.
+ if (fi.exists() && (url.scheme().isEmpty() || (url.scheme().length() == 1)))
qWarning("QNetworkAccessFileBackendFactory: URL has no schema set, use file:// for files");
if (fi.exists() || (op == QNetworkAccessManager::PutOperation && fi.dir().exists()))
return new QNetworkAccessFileBackend;
diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
index f56176a..70287a9 100644
--- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
@@ -1672,10 +1672,8 @@ void tst_QNetworkReply::getErrors()
QFETCH(QString, url);
QNetworkRequest request(url);
-#if defined(Q_OS_WIN) || defined (Q_OS_SYMBIAN)
if (qstrcmp(QTest::currentDataTag(), "empty-scheme-host") == 0 && QFileInfo(url).isAbsolute())
QTest::ignoreMessage(QtWarningMsg, "QNetworkAccessFileBackendFactory: URL has no schema set, use file:// for files");
-#endif
QNetworkReplyPtr reply = manager.get(request);
reply->setParent(this); // we have expect-fails
@@ -1691,10 +1689,9 @@ void tst_QNetworkReply::getErrors()
//qDebug() << reply->errorString();
QFETCH(int, error);
-#if defined(Q_OS_WIN) || defined (Q_OS_SYMBIAN)
if (QFileInfo(url).isAbsolute())
- QEXPECT_FAIL("empty-scheme-host", "this is expected to fail on Windows and Symbian, QTBUG-17731", Abort);
-#endif
+ QEXPECT_FAIL("empty-scheme-host", "this is expected to fail, QTBUG-17731", Abort);
+
QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort);
// the line below is not necessary
QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort);