summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Sasburg <simon.sasburg@gmail.com>2014-07-21 19:28:43 +0100
committerSimon Sasburg <simon.sasburg@gmail.com>2014-07-23 07:20:40 +0200
commit3905c6f00d9d11e01d6e211565d5ed58a59fc2d8 (patch)
treeb78f3e518bd879cd7c163da26162e595ad2ade9c
parentf713bd3e19406e02502fe1dc877f09ae57eca8df (diff)
Add QFileDevice::MemoryMapFlags::MapPrivateOption flag.
Passing this flag to QFileDevice::map() will allow writes to the mapped memory without modifying the file that was mapped. These writes will be lost when the memory is unmapped. Change-Id: I7d46b044fc370585de8c06fdb4059f1f1be12d7d Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
-rw-r--r--src/corelib/io/qfiledevice.cpp11
-rw-r--r--src/corelib/io/qfiledevice.h4
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp8
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp20
-rw-r--r--tests/auto/corelib/io/qfile/tst_qfile.cpp22
5 files changed, 51 insertions, 14 deletions
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index f7e58a7bed..33cb6037f5 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -680,6 +680,13 @@ bool QFileDevice::setPermissions(Permissions permissions)
function.
\value NoOptions No options.
+ \value MapPrivateOption The mapped memory will be private, so any
+ modifications will not be visible to other processes and will not
+ be written to disk. Any such modifications will be lost when the
+ memory is unmapped. It is unspecified whether modifications made
+ to the file made after the mapping is created will be visible through
+ the mapped memory. This flag is not supported on Windows CE.
+ This enum value was introduced in Qt 5.4.
*/
/*!
@@ -689,6 +696,10 @@ bool QFileDevice::setPermissions(Permissions permissions)
or a new file is opened with this object, any maps that have not been
unmapped will automatically be unmapped.
+ The mapping will have the same open mode as the file (read and/or write),
+ except when using MapPrivateOption, in which case it is always possible
+ to write to the mapped memory.
+
Any mapping options can be passed through \a flags.
Returns a pointer to the memory or 0 if there is an error.
diff --git a/src/corelib/io/qfiledevice.h b/src/corelib/io/qfiledevice.h
index fc2779086a..4b13ffe589 100644
--- a/src/corelib/io/qfiledevice.h
+++ b/src/corelib/io/qfiledevice.h
@@ -112,8 +112,10 @@ public:
virtual Permissions permissions() const;
virtual bool setPermissions(Permissions permissionSpec);
+ // ### Qt 6: rename to MemoryMapFlag & make it a QFlags
enum MemoryMapFlags {
- NoOptions = 0
+ NoOptions = 0,
+ MapPrivateOption = 0x0001
};
uchar *map(qint64 offset, qint64 size, MemoryMapFlags flags = NoOptions);
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index 064a1a511f..f9c6c8ab98 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -713,6 +713,12 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
if (openMode & QIODevice::ReadOnly) access |= PROT_READ;
if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE;
+ int sharemode = MAP_SHARED;
+ if (flags & QFileDevice::MapPrivateOption) {
+ sharemode = MAP_PRIVATE;
+ access |= PROT_WRITE;
+ }
+
#if defined(Q_OS_INTEGRITY)
int pageSize = sysconf(_SC_PAGESIZE);
#else
@@ -730,7 +736,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
realOffset &= ~(QT_OFF_T(pageSize - 1));
void *mapAddress = QT_MMAP((void*)0, realSize,
- access, MAP_SHARED, nativeHandle(), realOffset);
+ access, sharemode, nativeHandle(), realOffset);
if (MAP_FAILED != mapAddress) {
uchar *address = extra + static_cast<uchar*>(mapAddress);
maps[address] = QPair<int,size_t>(extra, realSize);
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index fb4107b95d..81aed5f7b4 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -965,6 +965,21 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
return 0;
}
+ // check/setup args to map
+ DWORD access = 0;
+ if (flags & QFileDevice::MapPrivateOption) {
+#ifdef FILE_MAP_COPY
+ access = FILE_MAP_COPY;
+#else
+ q->setError(QFile::UnspecifiedError, "MapPrivateOption unsupported");
+ return 0;
+#endif
+ } else if (openMode & QIODevice::WriteOnly) {
+ access = FILE_MAP_WRITE;
+ } else if (openMode & QIODevice::ReadOnly) {
+ access = FILE_MAP_READ;
+ }
+
if (mapHandle == NULL) {
// get handle to the file
HANDLE handle = fileHandle;
@@ -1011,11 +1026,6 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
}
}
- // setup args to map
- DWORD access = 0;
- if (openMode & QIODevice::ReadOnly) access = FILE_MAP_READ;
- if (openMode & QIODevice::WriteOnly) access = FILE_MAP_WRITE;
-
DWORD offsetHi = offset >> 32;
DWORD offsetLo = offset & Q_UINT64_C(0xffffffff);
SYSTEM_INFO sysinfo;
diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp
index 60d1517ed3..9ce931d78a 100644
--- a/tests/auto/corelib/io/qfile/tst_qfile.cpp
+++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp
@@ -3028,17 +3028,21 @@ void tst_QFile::mapResource()
void tst_QFile::mapOpenMode_data()
{
QTest::addColumn<int>("openMode");
+ QTest::addColumn<int>("flags");
- QTest::newRow("ReadOnly") << int(QIODevice::ReadOnly);
+ QTest::newRow("ReadOnly") << int(QIODevice::ReadOnly) << int(QFileDevice::NoOptions);
//QTest::newRow("WriteOnly") << int(QIODevice::WriteOnly); // this doesn't make sense
- QTest::newRow("ReadWrite") << int(QIODevice::ReadWrite);
- QTest::newRow("ReadOnly,Unbuffered") << int(QIODevice::ReadOnly | QIODevice::Unbuffered);
- QTest::newRow("ReadWrite,Unbuffered") << int(QIODevice::ReadWrite | QIODevice::Unbuffered);
+ QTest::newRow("ReadWrite") << int(QIODevice::ReadWrite) << int(QFileDevice::NoOptions);
+ QTest::newRow("ReadOnly,Unbuffered") << int(QIODevice::ReadOnly | QIODevice::Unbuffered) << int(QFileDevice::NoOptions);
+ QTest::newRow("ReadWrite,Unbuffered") << int(QIODevice::ReadWrite | QIODevice::Unbuffered) << int(QFileDevice::NoOptions);
+ QTest::newRow("ReadOnly + MapPrivate") << int(QIODevice::ReadOnly) << int(QFileDevice::MapPrivateOption);
+ QTest::newRow("ReadWrite + MapPrivate") << int(QIODevice::ReadWrite) << int(QFileDevice::MapPrivateOption);
}
void tst_QFile::mapOpenMode()
{
QFETCH(int, openMode);
+ QFETCH(int, flags);
static const qint64 fileSize = 4096;
QByteArray pattern(fileSize, 'A');
@@ -3060,11 +3064,15 @@ void tst_QFile::mapOpenMode()
// open according to our mode
QVERIFY(file.open(QIODevice::OpenMode(openMode)));
- uchar *memory = file.map(0, fileSize);
+ uchar *memory = file.map(0, fileSize, QFileDevice::MemoryMapFlags(flags));
+#if defined(Q_OS_WINCE)
+ QEXPECT_FAIL("ReadOnly + MapPrivate" , "Windows CE does not support MapPrivateOption.", Abort);
+ QEXPECT_FAIL("ReadWrite + MapPrivate", "Windows CE does not support MapPrivateOption.", Abort);
+#endif
QVERIFY(memory);
QVERIFY(memcmp(memory, pattern, fileSize) == 0);
- if (openMode & QIODevice::WriteOnly) {
+ if ((openMode & QIODevice::WriteOnly) || (flags & QFileDevice::MapPrivateOption)) {
// try to write to the file
*memory = 'a';
file.unmap(memory);
@@ -3073,7 +3081,7 @@ void tst_QFile::mapOpenMode()
file.seek(0);
char c;
QVERIFY(file.getChar(&c));
- QCOMPARE(c, 'a');
+ QCOMPARE(c, (flags & QFileDevice::MapPrivateOption) ? 'A' : 'a');
}
file.close();