From 12198d2ebbc36f3e916bc0a55b5d0e121dd5c643 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Tue, 1 Nov 2022 19:13:33 +0200 Subject: [PATCH] drop support for mapping QFile via mmap() Signed-off-by: Ivailo Monev --- src/core/io/qfile.cpp | 132 +++----------------------------- src/core/io/qfile.h | 3 - src/core/io/qfile_p.h | 2 - tests/auto/qfile/tst_qfile.cpp | 168 ----------------------------------------- 4 files changed, 9 insertions(+), 296 deletions(-) diff --git a/src/core/io/qfile.cpp b/src/core/io/qfile.cpp index 61d876ded..a281ab219 100644 --- a/src/core/io/qfile.cpp +++ b/src/core/io/qfile.cpp @@ -35,8 +35,6 @@ #define tr(X) QString::fromLatin1(X) #endif -#include - QT_BEGIN_NAMESPACE //************* QFilePrivate @@ -64,23 +62,6 @@ bool QFilePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const return metaData.exists(); } -bool QFilePrivate::unmap(uchar *ptr) -{ - if (!maps.contains(ptr)) { - setError(QFile::PermissionsError, qt_error_string(EACCES)); - return false; - } - - uchar *start = ptr - maps[ptr].first; - size_t len = maps[ptr].second; - if (::munmap(start, len) == -1) { - setError(QFile::UnspecifiedError, qt_error_string(errno)); - return false; - } - maps.remove(ptr); - return true; -} - bool QFilePrivate::openExternalFile(QIODevice::OpenMode mode, int _fd, QFile::FileHandleFlags handleFlags) { // Append implies WriteOnly. @@ -1023,96 +1004,6 @@ int QFile::handle() const } /*! - \since 4.4 - Maps \a size bytes of the file into memory starting at \a offset. A file - should be open for a map to succeed but the file does not need to stay - open after the memory has been mapped. When the QFile is destroyed - or a new file is opened with this object, any maps that have not been - unmapped will automatically be unmapped. - - Returns a pointer to the memory or 0 if there is an error. - - \sa unmap() - */ -uchar *QFile::map(qint64 offset, qint64 size) -{ - Q_D(QFile); - unsetError(); - if (!isOpen()) { - d->setError(QFile::PermissionsError, qt_error_string(EACCES)); - return 0; - } - - if (offset < 0 || offset != qint64(QT_OFF_T(offset)) - || size < 0 || quint64(size) > quint64(size_t(-1))) { - d->setError(QFile::UnspecifiedError, qt_error_string(EINVAL)); - return 0; - } - - // If we know the mapping will extend beyond EOF, fail early to avoid - // undefined behavior. Otherwise, let mmap have its say. - if (d->doStat(QFileSystemMetaData::SizeAttribute) - && (QT_OFF_T(size) > d->metaData.size() - QT_OFF_T(offset))) { - qWarning("QFile::map: Mapping a file beyond its size is not portable"); - } - - int access = 0; - if (openMode() & QIODevice::ReadOnly) access |= PROT_READ; - if (openMode() & QIODevice::WriteOnly) access |= PROT_WRITE; - - static const int pageSize = ::getpagesize(); - const int extra = offset % pageSize; - - if (quint64(size + extra) > quint64((size_t)-1)) { - d->setError(QFile::UnspecifiedError, qt_error_string(EINVAL)); - return 0; - } - - size_t realSize = (size_t)size + extra; - QT_OFF_T realOffset = QT_OFF_T(offset); - realOffset &= ~(QT_OFF_T(pageSize - 1)); - - void *mapAddress = QT_MMAP(nullptr, realSize, - access, MAP_SHARED, d->fd, realOffset); - if (mapAddress != MAP_FAILED) { - uchar *address = extra + static_cast(mapAddress); - d->maps[address] = QPair(extra, realSize); - return address; - } - - switch(errno) { - case EBADF: - d->setError(QFile::PermissionsError, qt_error_string(EACCES)); - break; - case ENFILE: - case ENOMEM: - d->setError(QFile::ResourceError, qt_error_string(errno)); - break; - case EINVAL: - // size are out of bounds - default: - d->setError(QFile::UnspecifiedError, qt_error_string(errno)); - break; - } - return 0; -} - -/*! - \since 4.4 - Unmaps the memory \a address. - - Returns true if the unmap succeeds; false otherwise. - - \sa map() - */ -bool QFile::unmap(uchar *address) -{ - Q_D(QFile); - unsetError(); - return d->unmap(address); -} - -/*! \fn QString QFile::name() const Use fileName() instead. @@ -1266,23 +1157,18 @@ void QFile::close() d->metaData.clear(); // Close the file if we created the handle. - int ret = 0; if (d->closeFileHandle) { - ret = qt_safe_close(d->fd); - } + const int ret = qt_safe_close(d->fd); - // We must reset these guys regardless; calling close again after a - // failed close causes crashes on some systems. - d->fd = -1; - QList keys = d->maps.keys(); - for (int i = 0; i < keys.count(); ++i) { - d->unmap(keys.at(i)); - } + // We must reset these guys regardless; calling close again after a + // failed close causes crashes on some systems. + d->fd = -1; - // Report errors. - if (ret != 0) { - d->setError(QFile::UnspecifiedError, qt_error_string(errno)); - return; + // Report errors. + if (ret != 0) { + d->setError(QFile::UnspecifiedError, qt_error_string(errno)); + return; + } } if (flushed) { diff --git a/src/core/io/qfile.h b/src/core/io/qfile.h index c4ecf2124..8c8cc5c2d 100644 --- a/src/core/io/qfile.h +++ b/src/core/io/qfile.h @@ -136,9 +136,6 @@ public: int handle() const; - uchar *map(qint64 offset, qint64 size); - bool unmap(uchar *address); - protected: #ifdef QT_NO_QOBJECT QFile(QFilePrivate &dd); diff --git a/src/core/io/qfile_p.h b/src/core/io/qfile_p.h index 604d4b3e0..1c727deac 100644 --- a/src/core/io/qfile_p.h +++ b/src/core/io/qfile_p.h @@ -49,13 +49,11 @@ protected: bool openExternalFile(QIODevice::OpenMode mode, int fd, QFile::FileHandleFlags handleFlags); bool doStat(QFileSystemMetaData::MetaDataFlags flags) const; - bool unmap(uchar *ptr); QFile::FileError error; QString errorString; QFileSystemEntry fileEntry; mutable QFileSystemMetaData metaData; - QHash > maps; int fd; bool closeFileHandle; diff --git a/tests/auto/qfile/tst_qfile.cpp b/tests/auto/qfile/tst_qfile.cpp index 20cd2995f..898321237 100644 --- a/tests/auto/qfile/tst_qfile.cpp +++ b/tests/auto/qfile/tst_qfile.cpp @@ -141,11 +141,6 @@ private slots: void readEof_data(); void readEof(); - void map_data(); - void map(); - void mapOpenMode_data(); - void mapOpenMode(); - void openStandardStreams(); void resize_data(); @@ -354,7 +349,6 @@ void tst_QFile::cleanupTestCase() QFile::remove("tst_qfile_copy.cpp"); QFile::remove("nullinline.txt"); QFile::remove("myLink2.lnk"); - QFile::remove("qfile_map_testfile"); QFile::remove("readAllBuffer.txt"); QFile::remove("qt_file.tmp"); QFile::remove("File.txt"); @@ -2372,168 +2366,6 @@ void tst_QFile::task167217() file.remove(); } -#define FILESIZE 65536 * 3 - -void tst_QFile::map_data() -{ - QTest::addColumn("fileSize"); - QTest::addColumn("offset"); - QTest::addColumn("size"); - QTest::addColumn("error"); - - QTest::newRow("zero") << FILESIZE << 0 << FILESIZE << QFile::NoError; - QTest::newRow("small, but 0") << FILESIZE << 30 << FILESIZE - 30 << QFile::NoError; - QTest::newRow("a page") << FILESIZE << 4096 << FILESIZE - 4096 << QFile::NoError; - QTest::newRow("+page") << FILESIZE << 5000 << FILESIZE - 5000 << QFile::NoError; - QTest::newRow("++page") << FILESIZE << 65576 << FILESIZE - 65576 << QFile::NoError; - QTest::newRow("bad size") << FILESIZE << 0 << -1 << QFile::ResourceError; - QTest::newRow("bad offset") << FILESIZE << -1 << 1 << QFile::UnspecifiedError; - QTest::newRow("zerozero") << FILESIZE << 0 << 0 << QFile::UnspecifiedError; -} - -void tst_QFile::map() -{ - QFETCH(int, fileSize); - QFETCH(int, offset); - QFETCH(int, size); - QFETCH(QFile::FileError, error); - - QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile"; - - if (QFile::exists(fileName)) { - QVERIFY(QFile::setPermissions(fileName, - QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser)); - QFile::remove(fileName); - } - QFile file(fileName); - - // invalid, not open - uchar *memory = file.map(0, size); - QVERIFY(!memory); - QCOMPARE(file.error(), QFile::PermissionsError); - QVERIFY(!file.unmap(memory)); - QCOMPARE(file.error(), QFile::PermissionsError); - - // make a file - QVERIFY(file.open(QFile::ReadWrite)); - QVERIFY(file.resize(fileSize)); - QVERIFY(file.flush()); - file.close(); - QVERIFY(file.open(QFile::ReadWrite)); - memory = file.map(offset, size); - if (error != QFile::NoError) { - - QVERIFY(file.error() != QFile::NoError); - return; - } - - QCOMPARE(file.error(), error); - QVERIFY(memory); - memory[0] = 'Q'; - QVERIFY(file.unmap(memory)); - QCOMPARE(file.error(), QFile::NoError); - - // Verify changes were saved - memory = file.map(offset, size); - QCOMPARE(file.error(), QFile::NoError); - QVERIFY(memory); - QVERIFY(memory[0] == 'Q'); - QVERIFY(file.unmap(memory)); - QCOMPARE(file.error(), QFile::NoError); - - // exotic test to make sure that multiple maps work - - // note: windows ce does not reference count mutliple maps - // it's essentially just the same reference but it - // cause a resource lock on the file which prevents it - // from being removed uchar *memory1 = file.map(0, file.size()); - uchar *memory1 = file.map(0, file.size()); - QCOMPARE(file.error(), QFile::NoError); - uchar *memory2 = file.map(0, file.size()); - QCOMPARE(file.error(), QFile::NoError); - QVERIFY(memory1); - QVERIFY(memory2); - QVERIFY(file.unmap(memory1)); - QCOMPARE(file.error(), QFile::NoError); - QVERIFY(file.unmap(memory2)); - QCOMPARE(file.error(), QFile::NoError); - memory1 = file.map(0, file.size()); - QCOMPARE(file.error(), QFile::NoError); - QVERIFY(memory1); - QVERIFY(file.unmap(memory1)); - QCOMPARE(file.error(), QFile::NoError); - - file.close(); - - if (!currentuserisroot) - // root always has permissions - { - // Change permissions on a file, just to confirm it would fail - QFile::Permissions originalPermissions = file.permissions(); - QVERIFY(file.setPermissions(QFile::ReadOther)); - QVERIFY(!file.open(QFile::ReadWrite)); - memory = file.map(offset, size); - QCOMPARE(file.error(), QFile::PermissionsError); - QVERIFY(!memory); - QVERIFY(file.setPermissions(originalPermissions)); - } - QVERIFY(file.remove()); -} - -void tst_QFile::mapOpenMode_data() -{ - QTest::addColumn("openMode"); - - QTest::newRow("ReadOnly") << int(QIODevice::ReadOnly); - //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); -} - -void tst_QFile::mapOpenMode() -{ - QFETCH(int, openMode); - static const qint64 fileSize = 4096; - - QByteArray pattern(fileSize, 'A'); - - QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile"; - if (QFile::exists(fileName)) { - QVERIFY(QFile::setPermissions(fileName, - QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser)); - QFile::remove(fileName); - } - QFile file(fileName); - - // make a file - QVERIFY(file.open(QFile::ReadWrite)); - QVERIFY(file.write(pattern)); - QVERIFY(file.flush()); - file.close(); - - // open according to our mode - QVERIFY(file.open(QIODevice::OpenMode(openMode))); - - uchar *memory = file.map(0, fileSize); - QVERIFY(memory); - QVERIFY(memcmp(memory, pattern, fileSize) == 0); - - if (openMode & QIODevice::WriteOnly) { - // try to write to the file - *memory = 'a'; - file.unmap(memory); - file.close(); - file.open(QIODevice::OpenMode(openMode)); - file.seek(0); - char c; - QVERIFY(file.getChar(&c)); - QCOMPARE(c, 'a'); - } - - file.close(); -} - void tst_QFile::openDirectory() { QFile f1(SRCDIR); -- 2.11.0