QAbstractFileEngine: Add permission argument to open()

The new argument allows atomic creation of files with non-default
permissions.

Task-number: QTBUG-79750
Change-Id: I4c49455b41f924ba87148302c8d0f77f5de0832b
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Ievgenii Meshcheriakov 2021-10-22 13:39:52 +02:00
parent 56bd1b76d2
commit 56e13acf4e
17 changed files with 71 additions and 27 deletions

View File

@ -383,10 +383,16 @@ QAbstractFileEngine::~QAbstractFileEngine()
The \a mode is an OR combination of QIODevice::OpenMode and The \a mode is an OR combination of QIODevice::OpenMode and
QIODevice::HandlingMode values. QIODevice::HandlingMode values.
If the file is created as a result of this call, its permissions are
set according to \a permissision. Null value means an implementation-
specific default.
*/ */
bool QAbstractFileEngine::open(QIODevice::OpenMode openMode) bool QAbstractFileEngine::open(QIODevice::OpenMode openMode,
std::optional<QFile::Permissions> permissions)
{ {
Q_UNUSED(openMode); Q_UNUSED(openMode);
Q_UNUSED(permissions);
return false; return false;
} }

View File

@ -124,7 +124,8 @@ public:
virtual ~QAbstractFileEngine(); virtual ~QAbstractFileEngine();
virtual bool open(QIODevice::OpenMode openMode); virtual bool open(QIODevice::OpenMode openMode,
std::optional<QFile::Permissions> permissions = std::nullopt);
virtual bool close(); virtual bool close();
virtual bool flush(); virtual bool flush();
virtual bool syncToDisk(); virtual bool syncToDisk();

View File

@ -226,7 +226,8 @@ void QFSFileEngine::setFileName(const QString &file)
/*! /*!
\reimp \reimp
*/ */
bool QFSFileEngine::open(QIODevice::OpenMode openMode) bool QFSFileEngine::open(QIODevice::OpenMode openMode,
std::optional<QFile::Permissions> permissions)
{ {
Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open", Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
"QFSFileEngine no longer supports buffered mode; upper layer must buffer"); "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
@ -250,7 +251,7 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode)
d->fh = nullptr; d->fh = nullptr;
d->fd = -1; d->fd = -1;
return d->nativeOpen(d->openMode); return d->nativeOpen(d->openMode, permissions);
} }
/*! /*!

View File

@ -59,6 +59,10 @@
#include <optional> #include <optional>
#ifdef Q_OS_UNIX
#include <sys/types.h> // for mode_t
#endif
#ifndef QT_NO_FSFILEENGINE #ifndef QT_NO_FSFILEENGINE
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -81,7 +85,7 @@ public:
explicit QFSFileEngine(const QString &file); explicit QFSFileEngine(const QString &file);
~QFSFileEngine(); ~QFSFileEngine();
bool open(QIODevice::OpenMode openMode) override; bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override;
bool open(QIODevice::OpenMode flags, FILE *fh); bool open(QIODevice::OpenMode flags, FILE *fh);
bool close() override; bool close() override;
bool flush() override; bool flush() override;
@ -156,7 +160,7 @@ public:
QFileSystemEntry fileEntry; QFileSystemEntry fileEntry;
QIODevice::OpenMode openMode; QIODevice::OpenMode openMode;
bool nativeOpen(QIODevice::OpenMode openMode); bool nativeOpen(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions);
bool openFh(QIODevice::OpenMode flags, FILE *fh); bool openFh(QIODevice::OpenMode flags, FILE *fh);
bool openFd(QIODevice::OpenMode flags, int fd); bool openFd(QIODevice::OpenMode flags, int fd);
bool nativeClose(); bool nativeClose();
@ -246,6 +250,10 @@ protected:
void init(); void init();
QAbstractFileEngine::FileFlags getPermissions(QAbstractFileEngine::FileFlags type) const; QAbstractFileEngine::FileFlags getPermissions(QAbstractFileEngine::FileFlags type) const;
#ifdef Q_OS_UNIX
bool nativeOpenImpl(QIODevice::OpenMode openMode, mode_t mode);
#endif
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -39,6 +39,7 @@
#include "qplatformdefs.h" #include "qplatformdefs.h"
#include "private/qabstractfileengine_p.h" #include "private/qabstractfileengine_p.h"
#include "private/qfiledevice_p.h"
#include "private/qfsfileengine_p.h" #include "private/qfsfileengine_p.h"
#include "private/qcore_unix_p.h" #include "private/qcore_unix_p.h"
#include "qfilesystementry_p.h" #include "qfilesystementry_p.h"
@ -107,7 +108,16 @@ static inline QString msgOpenDirectory()
/*! /*!
\internal \internal
*/ */
bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode,
std::optional<QFile::Permissions> permissions)
{
return nativeOpenImpl(openMode, permissions ? QtPrivate::toMode_t(*permissions) : 0666);
}
/*!
\internal
*/
bool QFSFileEnginePrivate::nativeOpenImpl(QIODevice::OpenMode openMode, mode_t mode)
{ {
Q_Q(QFSFileEngine); Q_Q(QFSFileEngine);
@ -118,7 +128,7 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
// Try to open the file in unbuffered mode. // Try to open the file in unbuffered mode.
do { do {
fd = QT_OPEN(fileEntry.nativeFilePath().constData(), flags, 0666); fd = QT_OPEN(fileEntry.nativeFilePath().constData(), flags, mode);
} while (fd == -1 && errno == EINTR); } while (fd == -1 && errno == EINTR);
// On failure, return and report the error. // On failure, return and report the error.

View File

@ -39,6 +39,7 @@
#include "qplatformdefs.h" #include "qplatformdefs.h"
#include "private/qabstractfileengine_p.h" #include "private/qabstractfileengine_p.h"
#include "private/qfiledevice_p.h"
#include "private/qfsfileengine_p.h" #include "private/qfsfileengine_p.h"
#include "qfilesystemengine_p.h" #include "qfilesystemengine_p.h"
#include <qdebug.h> #include <qdebug.h>
@ -95,7 +96,8 @@ QString QFSFileEnginePrivate::longFileName(const QString &path)
/* /*
\internal \internal
*/ */
bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode,
std::optional<QFile::Permissions> permissions)
{ {
Q_Q(QFSFileEngine); Q_Q(QFSFileEngine);
@ -115,11 +117,14 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
? OPEN_ALWAYS ? OPEN_ALWAYS
: OPEN_EXISTING; : OPEN_EXISTING;
// Create the file handle. // Create the file handle.
SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE }; QNativeFilePermissions nativePermissions(permissions, false);
if (!nativePermissions.isOk())
return false;
fileHandle = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(), fileHandle = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(),
accessRights, accessRights,
shareMode, shareMode,
&securityAtts, nativePermissions.securityAttributes(),
creationDisp, creationDisp,
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
NULL); NULL);

View File

@ -1409,8 +1409,11 @@ void QResourceFileEngine::setFileName(const QString &file)
d->resource.setFileName(file); d->resource.setFileName(file);
} }
bool QResourceFileEngine::open(QIODevice::OpenMode flags) bool QResourceFileEngine::open(QIODevice::OpenMode flags,
std::optional<QFile::Permissions> permissions)
{ {
Q_UNUSED(permissions);
Q_D(QResourceFileEngine); Q_D(QResourceFileEngine);
if (d->resource.fileName().isEmpty()) { if (d->resource.fileName().isEmpty()) {
qWarning("QResourceFileEngine::open: Missing file name"); qWarning("QResourceFileEngine::open: Missing file name");

View File

@ -66,7 +66,7 @@ public:
void setFileName(const QString &file) override; void setFileName(const QString &file) override;
bool open(QIODevice::OpenMode flags) override; bool open(QIODevice::OpenMode flags, std::optional<QFile::Permissions> permissions) override;
bool close() override; bool close() override;
bool flush() override; bool flush() override;
qint64 size() const override; qint64 size() const override;

View File

@ -340,7 +340,8 @@ void QTemporaryFileEngine::setFileName(const QString &file)
QFSFileEngine::setFileName(file); QFSFileEngine::setFileName(file);
} }
bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode,
std::optional<QFile::Permissions> permissions)
{ {
Q_D(QFSFileEngine); Q_D(QFSFileEngine);
Q_ASSERT(!isReallyOpen()); Q_ASSERT(!isReallyOpen());
@ -348,7 +349,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
openMode |= QIODevice::ReadWrite; openMode |= QIODevice::ReadWrite;
if (!filePathIsTemplate) if (!filePathIsTemplate)
return QFSFileEngine::open(openMode); return QFSFileEngine::open(openMode, permissions);
QTemporaryFileName tfn(templateName); QTemporaryFileName tfn(templateName);

View File

@ -133,7 +133,7 @@ public:
bool isReallyOpen() const; bool isReallyOpen() const;
void setFileName(const QString &file) override; void setFileName(const QString &file) override;
bool open(QIODevice::OpenMode flags) override; bool open(QIODevice::OpenMode flags, std::optional<QFile::Permissions> permissions) override;
bool remove() override; bool remove() override;
bool rename(const QString &newName) override; bool rename(const QString &newName) override;
bool renameOverwrite(const QString &newName) override; bool renameOverwrite(const QString &newName) override;

View File

@ -54,8 +54,10 @@ AndroidContentFileEngine::AndroidContentFileEngine(const QString &f)
setFileName(f); setFileName(f);
} }
bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode) bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode,
std::optional<QFile::Permissions> permissions)
{ {
Q_UNUSED(permissions);
QString openModeStr; QString openModeStr;
if (openMode & QFileDevice::ReadOnly) { if (openMode & QFileDevice::ReadOnly) {
openModeStr += QLatin1Char('r'); openModeStr += QLatin1Char('r');

View File

@ -46,7 +46,7 @@ class AndroidContentFileEngine : public QFSFileEngine
{ {
public: public:
AndroidContentFileEngine(const QString &fileName); AndroidContentFileEngine(const QString &fileName);
bool open(QIODevice::OpenMode openMode) override; bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override;
qint64 size() const override; qint64 size() const override;
FileFlags fileFlags(FileFlags type = FileInfoAll) const override; FileFlags fileFlags(FileFlags type = FileInfoAll) const override;
QString fileName(FileName file = DefaultName) const override; QString fileName(FileName file = DefaultName) const override;

View File

@ -261,8 +261,10 @@ public:
close(); close();
} }
bool open(QIODevice::OpenMode openMode) override bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override
{ {
Q_UNUSED(permissions);
if (m_isFolder || (openMode & QIODevice::WriteOnly)) if (m_isFolder || (openMode & QIODevice::WriteOnly))
return false; return false;
close(); close();
@ -358,7 +360,7 @@ public:
m_fileName = cleanedAssetPath(file); m_fileName = cleanedAssetPath(file);
switch (FolderIterator::fileType(m_fileName)) { switch (FolderIterator::fileType(m_fileName)) {
case AssetItem::Type::File: case AssetItem::Type::File:
open(QIODevice::ReadOnly); open(QIODevice::ReadOnly, std::nullopt);
break; break;
case AssetItem::Type::Folder: case AssetItem::Type::Folder:
m_isFolder = true; m_isFolder = true;

View File

@ -54,7 +54,7 @@ public:
QIOSFileEngineAssetsLibrary(const QString &fileName); QIOSFileEngineAssetsLibrary(const QString &fileName);
~QIOSFileEngineAssetsLibrary(); ~QIOSFileEngineAssetsLibrary();
bool open(QIODevice::OpenMode openMode) override; bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override;
bool close() override; bool close() override;
FileFlags fileFlags(FileFlags type) const override; FileFlags fileFlags(FileFlags type) const override;
qint64 size() const override; qint64 size() const override;

View File

@ -353,8 +353,11 @@ ALAsset *QIOSFileEngineAssetsLibrary::loadAsset() const
return m_data->m_asset; return m_data->m_asset;
} }
bool QIOSFileEngineAssetsLibrary::open(QIODevice::OpenMode openMode) bool QIOSFileEngineAssetsLibrary::open(QIODevice::OpenMode openMode,
std::optional<QFile::Permissions> permissions)
{ {
Q_UNUSED(permissions);
if (openMode & (QIODevice::WriteOnly | QIODevice::Text)) if (openMode & (QIODevice::WriteOnly | QIODevice::Text))
return false; return false;
return loadAsset(); return loadAsset();

View File

@ -76,8 +76,10 @@ public:
{ {
} }
bool open(QIODevice::OpenMode openMode) override bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override
{ {
Q_UNUSED(permissions);
if (openForRead_ || openForWrite_) { if (openForRead_ || openForWrite_) {
qWarning("%s: file is already open for %s", qWarning("%s: file is already open for %s",
Q_FUNC_INFO, Q_FUNC_INFO,

View File

@ -263,7 +263,7 @@ void tst_qfile::readBigFile()
#ifdef QT_BUILD_INTERNAL #ifdef QT_BUILD_INTERNAL
case QFSFileEngineBenchmark: { case QFSFileEngineBenchmark: {
QFSFileEngine fse(tempDir.filename); QFSFileEngine fse(tempDir.filename);
fse.open(QIODevice::ReadOnly|textMode|bufferedMode); fse.open(QIODevice::ReadOnly | textMode | bufferedMode, std::nullopt);
QBENCHMARK { QBENCHMARK {
//qWarning() << fse.supportsExtension(QAbstractFileEngine::AtEndExtension); //qWarning() << fse.supportsExtension(QAbstractFileEngine::AtEndExtension);
while (fse.read(buffer, blockSize)) {} while (fse.read(buffer, blockSize)) {}
@ -349,7 +349,7 @@ void tst_qfile::seek()
#ifdef QT_BUILD_INTERNAL #ifdef QT_BUILD_INTERNAL
case QFSFileEngineBenchmark: { case QFSFileEngineBenchmark: {
QFSFileEngine fse(tempDir.filename); QFSFileEngine fse(tempDir.filename);
fse.open(QIODevice::ReadOnly | QIODevice::Unbuffered); fse.open(QIODevice::ReadOnly | QIODevice::Unbuffered, std::nullopt);
QBENCHMARK { QBENCHMARK {
i=(i+1)%sp_size; i=(i+1)%sp_size;
fse.seek(seekpos[i]); fse.seek(seekpos[i]);
@ -426,7 +426,7 @@ void tst_qfile::open()
case QFSFileEngineBenchmark: { case QFSFileEngineBenchmark: {
QBENCHMARK { QBENCHMARK {
QFSFileEngine fse(tempDir.filename); QFSFileEngine fse(tempDir.filename);
fse.open(QIODevice::ReadOnly | QIODevice::Unbuffered); fse.open(QIODevice::ReadOnly | QIODevice::Unbuffered, std::nullopt);
fse.close(); fse.close();
} }
} }
@ -550,7 +550,7 @@ void tst_qfile::readSmallFiles()
QList<QFSFileEngine*> fileList; QList<QFSFileEngine*> fileList;
for (const QString &file : files) { for (const QString &file : files) {
QFSFileEngine *fse = new QFSFileEngine(tempDir.filePath(file)); QFSFileEngine *fse = new QFSFileEngine(tempDir.filePath(file));
fse->open(QIODevice::ReadOnly|textMode|bufferedMode); fse->open(QIODevice::ReadOnly | textMode | bufferedMode, std::nullopt);
fileList.append(fse); fileList.append(fse);
} }