summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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");