diff options
-rw-r--r-- | src/corelib/io/qfile.cpp | 49 | ||||
-rw-r--r-- | src/corelib/io/qfile.h | 1 | ||||
-rw-r--r-- | tests/auto/corelib/io/qfile/tst_qfile.cpp | 52 |
3 files changed, 101 insertions, 1 deletions
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index bdbc5d3e44..2329613f45 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -886,7 +886,9 @@ QFile::copy(const QString &fileName, const QString &newName) \note In \l{QIODevice::}{WriteOnly} or \l{QIODevice::}{ReadWrite} mode, if the relevant file does not already exist, this function - will try to create a new file before opening it. + will try to create a new file before opening it. The file will be + created with mode 0666 masked by the umask on POSIX systems, and + with permissions inherited from the parent directory on Windows. \sa QIODevice::OpenMode, setFileName() */ @@ -921,6 +923,51 @@ bool QFile::open(OpenMode mode) /*! \overload + If the file does not exist and \a mode implies creating it, it is created + with the specified \a permissions. + + On POSIX systems the actual permissions are influenced by the + value of \c umask. + + On Windows the permissions are emulated using ACLs. These ACLs may be in non-canonical + order when the group is granted less permissions than others. Files and directories with + such permissions will generate warnings when the Security tab of the Properties dialog + is opened. Granting the group all permissions granted to others avoids such warnings. + + \sa QIODevice::OpenMode, setFileName() + \since 6.3 +*/ +bool QFile::open(OpenMode mode, QFile::Permissions permissions) +{ + Q_D(QFile); + if (isOpen()) + return file_already_open(*this); + // Either Append or NewOnly implies WriteOnly + if (mode & (Append | NewOnly)) + mode |= WriteOnly; + unsetError(); + if ((mode & (ReadOnly | WriteOnly)) == 0) { + qWarning("QIODevice::open: File access not specified"); + return false; + } + + // QIODevice provides the buffering, so there's no need to request it from the file engine. + if (d->engine()->open(mode | QIODevice::Unbuffered, permissions)) { + QIODevice::open(mode); + if (mode & Append) + seek(size()); + return true; + } + QFile::FileError err = d->fileEngine->error(); + if (err == QFile::UnspecifiedError) + err = QFile::OpenError; + d->setError(err, d->fileEngine->errorString()); + return false; +} + +/*! + \overload + Opens the existing file handle \a fh in the given \a mode. \a handleFlags may be used to specify additional options. Returns \c true if successful; otherwise returns \c false. diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h index 70b094d3a9..71246751fe 100644 --- a/src/corelib/io/qfile.h +++ b/src/corelib/io/qfile.h @@ -284,6 +284,7 @@ public: #endif // QT_CONFIG(cxx17_filesystem) bool open(OpenMode flags) override; + bool open(OpenMode flags, Permissions permissions); bool open(FILE *f, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle); bool open(int fd, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle); diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index afcd2c2a7e..8ea01b4680 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -183,6 +183,8 @@ private slots: void ungetChar(); void createFile(); void createFileNewOnly(); + void createFilePermissions_data(); + void createFilePermissions(); void openFileExistingOnly(); void append(); void permissions_data(); @@ -1268,6 +1270,56 @@ void tst_QFile::createFileNewOnly() QFile::remove("createme.txt"); } +void tst_QFile::createFilePermissions_data() +{ + QTest::addColumn<QFile::Permissions>("permissions"); + + for (int u = 0; u < 8; ++u) { + for (int g = 0; g < 8; ++g) { + for (int o = 0; o < 8; ++o) { + auto permissions = QFileDevice::Permissions::fromInt((u << 12) | (g << 4) | o); + QTest::addRow("%04x", permissions.toInt()) << permissions; + } + } + } +} + +void tst_QFile::createFilePermissions() +{ + QFETCH(QFile::Permissions, permissions); + +#ifdef Q_OS_WIN + QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup); + ++qt_ntfs_permission_lookup; +#endif +#ifdef Q_OS_UNIX + auto restoreMask = qScopeGuard([oldMask = umask(0)] { umask(oldMask); }); +#endif + + const QFile::Permissions setPermissions = { + QFile::ReadOther, QFile::WriteOther, QFile::ExeOther, + QFile::ReadGroup, QFile::WriteGroup, QFile::ExeGroup, + QFile::ReadOwner, QFile::WriteOwner, QFile::ExeOwner + }; + + const QString fileName = u"createme.txt"_qs; + + QFile::remove(fileName); + QVERIFY(!QFile::exists(fileName)); + + QFile f(fileName); + auto removeFile = qScopeGuard([&f] { + f.close(); + f.remove(); + }); + QVERIFY2(f.open(QIODevice::WriteOnly, permissions), msgOpenFailed(f).constData()); + + QVERIFY(QFile::exists(fileName)); + + auto actualPermissions = QFileInfo(fileName).permissions(); + QCOMPARE(actualPermissions & setPermissions, permissions); +} + void tst_QFile::openFileExistingOnly() { QFile::remove("dontcreateme.txt"); |