QDir: add mkpath/mkdir overloads taking std::optional<Permissions>

std::optional:
- it's already used in private API in QFileSystemEngine and
  QAbstractFileEngine and its subclasses, so there is no extra overhead
- less code duplication as it lets the existing overloads call the new
  ones with std::nullopt to make it use the platform default permissions
- adding a new enumerator, e.g. "PlatormDefault", wouldn't work:
    - 0x0 is ambiguous with setting the permissions to nothing
    - the new enumerator mustn't set any other permission bits, so it'll
      have to be > std::numeric_limits<short>::max(), which is
      potentially BiC as the underlying type of the enum will become int

[ChangeLog][QtCore][QDir] Added mkdir() method that takes a
std::optional<QFile::Permissions>; the new method transparently replaces
the older mkdir() overloads.

[ChangeLog][QtCore][QDir] Added mkpath() method that takes a
std::optional<QFile::Permissions>; this new method transparently
replaces the older mkpath() overload.

Task-number: QTBUG-132633
Change-Id: Ic2cd1e01e6ad1a2b6d3a6180c41b6a0b260a4e55
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Ahmad Samir 2025-01-21 01:26:01 +02:00
parent 23981aae0e
commit 4275dfb7bf
4 changed files with 72 additions and 43 deletions

View File

@ -1380,6 +1380,23 @@ QUuid::Version QUuid::version() const noexcept
#if QT_CORE_REMOVED_SINCE(6, 10)
#include "qdir.h"
bool QDir::mkdir(const QString &dirName) const
{
return mkdir(dirName, std::nullopt);
}
bool QDir::mkdir(const QString &dirName, QFile::Permissions permissions) const
{
return mkdir(dirName, std::optional{permissions});
}
bool QDir::mkpath(const QString &dirPath) const
{
return mkpath(dirPath, std::nullopt);
}
#if QT_CONFIG(future)
#include "qfuture.h" // for ContinuationWrapper
#include "qfutureinterface.h"

View File

@ -1495,8 +1495,13 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter
/*!
Creates a sub-directory called \a dirName with the given \a permissions.
If \a permissions is \c std::nullopt (the default) this function will
set the default permissions.
Returns \c true on success; returns \c false if the operation failed or
the directory already existed.
\a dirName already existed.
If \a dirName already existed, this method won't change its permissions.
//! [dir-creation-mode-bits-unix]
On POSIX systems \a permissions are modified by the
@ -1505,18 +1510,24 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter
bits might be disabled.
//! [dir-creation-mode-bits-unix]
//! [windows-permissions-acls]
On Windows, by default, a new directory inherits its permissions from its
parent directory. \a 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.
//! [windows-permissions-acls]
\note Qt 6.10 added the \a permissions parameter. To get the old behavior
(using the default platform-specific permissions) of \c{mkdir(const QString &)}
set \a permissions to \c std::nullopt (the default). This new method also
transparently replaces the \c {mkdir(const QString &, QFile::Permissions)}
overload.
\sa rmdir(), mkpath(), rmpath()
\since 6.3
*/
bool QDir::mkdir(const QString &dirName, QFile::Permissions permissions) const
bool QDir::mkdir(const QString &dirName, std::optional<QFile::Permissions> permissions) const
{
Q_D(const QDir);
@ -1531,40 +1542,6 @@ bool QDir::mkdir(const QString &dirName, QFile::Permissions permissions) const
return d->fileEngine->mkdir(fn, false, permissions);
}
/*!
\overload
Creates a sub-directory called \a dirName with the platform-specific
default permissions.
Returns \c true on success; returns \c false if the operation failed or
the directory already existed.
//! [windows-permissions-acls]
On Windows, by default, a new directory inherits its permissions from its
parent directory. 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.
//! [windows-permissions-acls]
\sa rmdir(), mkpath(), rmpath()
*/
bool QDir::mkdir(const QString &dirName) const
{
Q_D(const QDir);
if (dirName.isEmpty()) {
qWarning("QDir::mkdir: Empty or null file name");
return false;
}
QString fn = filePath(dirName);
if (!d->fileEngine)
return QFileSystemEngine::mkdir(QFileSystemEntry(fn));
return d->fileEngine->mkdir(fn, false);
}
/*!
Removes the directory specified by \a dirName.
@ -1594,16 +1571,28 @@ bool QDir::rmdir(const QString &dirName) const
Creates a directory named \a dirPath.
If \a dirPath doesn't already exist, this method will create it - along with
any nonexistent parent directories - with the default permissions.
any nonexistent parent directories - with \a permissions.
If \a dirPath already existed, this method won't change its permissions;
the same goes for any already existing parent directories.
If \a permissions is \c std::nullopt (the default value) this function will
set the default permissions.
Returns \c true on success or if \a dirPath already existed; otherwise
returns \c false.
\include qdir.cpp dir-creation-mode-bits-unix
\include qdir.cpp windows-permissions-acls
\note Qt 6.10 added the \a permissions parameter. To get the old behavior
(using the default platform-specific permissions) of \c{mkpath(const QString &)}
set \a permissions to \c std::nullopt (the default).
\sa rmpath(), mkdir(), rmdir()
*/
bool QDir::mkpath(const QString &dirPath) const
bool QDir::mkpath(const QString &dirPath, std::optional<QFile::Permissions> permissions) const
{
Q_D(const QDir);
@ -1614,8 +1603,8 @@ bool QDir::mkpath(const QString &dirPath) const
QString fn = filePath(dirPath);
if (!d->fileEngine)
return QFileSystemEngine::mkpath(QFileSystemEntry(fn));
return d->fileEngine->mkdir(fn, true);
return QFileSystemEngine::mkpath(QFileSystemEntry(fn), permissions);
return d->fileEngine->mkdir(fn, true, permissions);
}
/*!

View File

@ -169,10 +169,16 @@ public:
QFileInfoList entryInfoList(const QStringList &nameFilters, Filters filters = NoFilter,
SortFlags sort = NoSort) const;
#if QT_CORE_REMOVED_SINCE(6, 10)
bool mkdir(const QString &dirName) const;
bool mkdir(const QString &dirName, QFile::Permissions permissions) const;
#endif
bool mkdir(const QString &dirName, std::optional<QFile::Permissions> p = std::nullopt) const;
bool rmdir(const QString &dirName) const;
#if QT_CORE_REMOVED_SINCE(6, 10)
bool mkpath(const QString &dirPath) const;
#endif
bool mkpath(const QString &dirPath, std::optional<QFile::Permissions> p = std::nullopt) const;
bool rmpath(const QString &dirPath) const;
bool removeRecursively();

View File

@ -92,7 +92,7 @@ private slots:
void mkdirRmdir();
void mkdirOnSymlink();
void mkdirWithPermissions_data();
void mkdirWithPermissions();
void mkdirWithPermissions(); // QDir::{mkdir,mkpath}()
void makedirReturnCode();
@ -508,6 +508,7 @@ void tst_QDir::mkdirWithPermissions()
QFile::ReadOwner, QFile::WriteOwner, QFile::ExeOwner
};
{
const QString path = u"tmpdir"_s;
QDir dir;
auto deleteDirectory = qScopeGuard([&dir, &path] { dir.rmdir(path); });
@ -519,6 +520,22 @@ void tst_QDir::mkdirWithPermissions()
deleteDirectory.dismiss();
}
{
// On Unix we need at least 'wx' permissions to be able to create "subdir"
if (permissions.testFlags(QFile::WriteOwner | QFile::ExeOwner)) {
const QString path = u"mkpath-tmpdir/subdir"_s;
QDir dir;
auto deleteDirectory = qScopeGuard([&dir, &path] { dir.rmpath(path); });
QVERIFY(dir.mkpath(path, permissions));
auto actualPermissions = QFileInfo(path).permissions();
QCOMPARE(actualPermissions & setPermissions, permissions);
QVERIFY(dir.rmpath(path));
deleteDirectory.dismiss();
}
}
}
void tst_QDir::makedirReturnCode()
{
QString dirName = QString::fromLatin1("makedirReturnCode");