summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIevgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>2021-10-22 13:52:27 +0200
committerIevgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>2021-12-04 01:27:11 +0100
commit83f2f27bb6cac0b85cdb47365347493d8dc5feb2 (patch)
tree2201536d1321bd036b1fae878a02a46853c54b0d
parent56e13acf4eaaaff69156faa21d0a560fb93091d5 (diff)
QFile: Add open() overload that accepts permissions argument
The new overload allows creation of files with non-default permissions. This is useful when files need to be created with more restrictive permissions than the default ones, and removes the time window when such files are available with less restrictive permissions. [ChangeLog][QtCore][QFile] Added QDir::open() overload that accepts permissions argument. Fixes: QTBUG-79750 Change-Id: Iddfced3c324e03f2c53f421c9b31c76dee82df58 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r--src/corelib/io/qfile.cpp49
-rw-r--r--src/corelib/io/qfile.h1
-rw-r--r--tests/auto/corelib/io/qfile/tst_qfile.cpp52
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");