diff options
author | Simon Sasburg <simon.sasburg@gmail.com> | 2014-07-21 19:28:43 +0100 |
---|---|---|
committer | Simon Sasburg <simon.sasburg@gmail.com> | 2014-07-23 07:20:40 +0200 |
commit | 3905c6f00d9d11e01d6e211565d5ed58a59fc2d8 (patch) | |
tree | b78f3e518bd879cd7c163da26162e595ad2ade9c | |
parent | f713bd3e19406e02502fe1dc877f09ae57eca8df (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.cpp | 11 | ||||
-rw-r--r-- | src/corelib/io/qfiledevice.h | 4 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_unix.cpp | 8 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_win.cpp | 20 | ||||
-rw-r--r-- | tests/auto/corelib/io/qfile/tst_qfile.cpp | 22 |
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(); |