summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qfile.cpp')
-rw-r--r--src/corelib/io/qfile.cpp295
1 files changed, 226 insertions, 69 deletions
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index bdbc5d3e44..6da428f58c 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "qdebug.h"
@@ -61,6 +25,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_DECL_COLD_FUNCTION
static bool file_already_open(QFile &file, const char *where = nullptr)
{
@@ -110,7 +76,7 @@ QFilePrivate::openExternalFile(QIODevice::OpenMode flags, FILE *fh, QFile::FileH
QAbstractFileEngine *QFilePrivate::engine() const
{
if (!fileEngine)
- fileEngine.reset(QAbstractFileEngine::create(fileName));
+ fileEngine = QAbstractFileEngine::create(fileName);
return fileEngine.get();
}
@@ -184,13 +150,20 @@ QAbstractFileEngine *QFilePrivate::engine() const
data and operator>>() to read it back. See the class
documentation for details.
- When you use QFile, QFileInfo, and QDir to access the file system
- with Qt, you can use Unicode file names. On Unix, these file
- names are converted to an 8-bit encoding. If you want to use
- standard C++ APIs (\c <cstdio> or \c <iostream>) or
- platform-specific APIs to access files instead of QFile, you can
- use the encodeName() and decodeName() functions to convert
- between Unicode file names and 8-bit file names.
+ \section1 Signals
+
+ Unlike other QIODevice implementations, such as QTcpSocket, QFile does not
+ emit the aboutToClose(), bytesWritten(), or readyRead() signals. This
+ implementation detail means that QFile is not suitable for reading and
+ writing certain types of files, such as device files on Unix platforms.
+
+ \section1 Platform Specific Issues
+
+ \l{Input/Output and Networking}{Qt APIs related to I/O} use UTF-16 based
+ QStrings to represent file paths. Standard C++ APIs (\c <cstdio> or
+ \c <iostream>) or platform-specific APIs however often need a 8-bit encoded
+ path. You can use encodeName() and decodeName() to convert between both
+ representations.
On Unix, there are some special system files (e.g. in \c /proc) for which
size() will always return 0, yet you may still be able to read more data
@@ -203,15 +176,6 @@ QAbstractFileEngine *QFilePrivate::engine() const
\snippet file/file.cpp 3
- \section1 Signals
-
- Unlike other QIODevice implementations, such as QTcpSocket, QFile does not
- emit the aboutToClose(), bytesWritten(), or readyRead() signals. This
- implementation detail means that QFile is not suitable for reading and
- writing certain types of files, such as device files on Unix platforms.
-
- \section1 Platform Specific Issues
-
File permissions are handled differently on Unix-like systems and
Windows. In a non \l{QIODevice::isWritable()}{writable}
directory on Unix-like systems, files cannot be created. This is not always
@@ -226,6 +190,8 @@ QAbstractFileEngine *QFilePrivate::engine() const
function mostly useless for NTFS volumes. It may still be of use for USB
sticks that use VFAT file systems. POSIX ACLs are not manipulated, either.
+ \include android-content-uri-limitations.qdocinc
+
\sa QTextStream, QDataStream, QFileInfo, QDir, {The Qt Resource System}
*/
@@ -260,6 +226,15 @@ QFile::QFile(QObject *parent)
}
/*!
Constructs a new file object to represent the file with the given \a name.
+
+//! [qfile-explicit-constructor-note]
+ \note In versions up to and including Qt 6.8, this constructor is
+ implicit, for backward compatibility. Starting from Qt 6.9 this
+ constructor is unconditionally \c{explicit}. Users can force this
+ constructor to be \c{explicit} even in earlier versions of Qt by
+ defining the \c{QT_EXPLICIT_QFILE_CONSTRUCTION_FROM_PATH} macro
+ before including any Qt header.
+//! [qfile-explicit-constructor-note]
*/
QFile::QFile(const QString &name)
: QFileDevice(*new QFilePrivate, nullptr)
@@ -347,10 +322,10 @@ QFile::setFileName(const QString &name)
/*!
\fn QByteArray QFile::encodeName(const QString &fileName)
- Converts \a fileName to the local 8-bit
- encoding determined by the user's locale. This is sufficient for
- file names that the user chooses. File names hard-coded into the
- application should only use 7-bit ASCII filename characters.
+ Converts \a fileName to an 8-bit encoding that you can use in native
+ APIs. On Windows, the encoding is the one from active Windows (ANSI)
+ codepage. On other platforms, this is UTF-8, for \macos in decomposed
+ form (NFD).
\sa decodeName()
*/
@@ -484,6 +459,24 @@ QFile::remove(const QString &fileName)
and sets the fileName() to the path at which the file can be found within the trash;
otherwise returns \c false.
+//! [move-to-trash-common]
+ The time for this function to run is independent of the size of the file
+ being trashed. If this function is called on a directory, it may be
+ proportional to the number of files being trashed.
+
+ This function uses the Windows and \macos APIs to perform the trashing on
+ those two operating systems. Elsewhere (Unix systems), this function
+ implements the \l{FreeDesktop.org Trash specification version 1.0}.
+
+ \note When using the FreeDesktop.org Trash implementation, this function
+ will fail if it is unable to move the files to the trash location by way of
+ file renames and hardlinks. This condition arises if the file being trashed
+ resides on a volume (mount point) on which the current user does not have
+ permission to create the \c{.Trash} directory, or with some unusual
+ filesystem types or configurations (such as sub-volumes that aren't
+ themselves mount points).
+//! [move-to-trash-common]
+
\note On systems where the system API doesn't report the location of the file in the
trash, fileName() will be set to the null string once the file has been moved. On
systems that don't have a trash can, this function always returns false.
@@ -521,9 +514,12 @@ QFile::moveToTrash()
and sets \a pathInTrash (if provided) to the path at which the file can be found within
the trash; otherwise returns \c false.
+ \include qfile.cpp move-to-trash-common
+
\note On systems where the system API doesn't report the path of the file in the
trash, \a pathInTrash will be set to the null string once the file has been moved.
On systems that don't have a trash can, this function always returns false.
+
*/
bool
QFile::moveToTrash(const QString &fileName, QString *pathInTrash)
@@ -588,7 +584,7 @@ QFile::rename(const QString &newName)
return false;
}
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) && QT_CONFIG(temporaryfile)
// rename() on Linux simply does nothing when renaming "foo" to "Foo" on a case-insensitive
// FS, such as FAT32. Move the file away and rename in 2 steps to work around.
QTemporaryFileName tfn(d->fileName);
@@ -616,7 +612,7 @@ QFile::rename(const QString &newName)
// report both errors
d->setError(QFile::RenameError,
tr("Error while renaming: %1").arg(error.toString())
- + QLatin1Char('\n')
+ + u'\n'
+ tr("Unable to restore from %1: %2").
arg(QDir::toNativeSeparators(tmp.filePath()), error2.toString()));
return false;
@@ -759,6 +755,9 @@ QFile::link(const QString &fileName, const QString &linkName)
\include qfile-copy.qdocinc
+ \note On Android, this operation is not yet supported for \c content
+ scheme URIs.
+
\sa setFileName()
*/
@@ -789,8 +788,8 @@ QFile::copy(const QString &newName)
error = true;
d->setError(QFile::CopyError, tr("Cannot open %1 for input").arg(d->fileName));
} else {
- const auto fileTemplate = QLatin1String("%1/qt_temp.XXXXXX");
-#ifdef QT_NO_TEMPORARYFILE
+ const auto fileTemplate = "%1/qt_temp.XXXXXX"_L1;
+#if !QT_CONFIG(temporaryfile)
QFile out(fileTemplate.arg(QFileInfo(newName).path()));
if (!out.open(QIODevice::ReadWrite))
error = true;
@@ -803,9 +802,9 @@ QFile::copy(const QString &newName)
}
#endif
if (error) {
+ d->setError(QFile::CopyError, tr("Cannot open for output: %1").arg(out.errorString()));
out.close();
close();
- d->setError(QFile::CopyError, tr("Cannot open for output: %1").arg(out.errorString()));
} else {
if (!d->engine()->cloneTo(out.d_func()->engine())) {
char block[4096];
@@ -817,7 +816,8 @@ QFile::copy(const QString &newName)
totalRead += in;
if (in != out.write(block, in)) {
close();
- d->setError(QFile::CopyError, tr("Failure to write block"));
+ d->setError(QFile::CopyError, tr("Failure to write block: %1")
+ .arg(out.errorString()));
error = true;
break;
}
@@ -837,10 +837,11 @@ QFile::copy(const QString &newName)
if (!out.rename(newName)) {
error = true;
close();
- d->setError(QFile::CopyError, tr("Cannot create %1 for output").arg(newName));
+ d->setError(QFile::CopyError, tr("Cannot create %1 for output: %2")
+ .arg(newName, out.errorString()));
}
}
-#ifdef QT_NO_TEMPORARYFILE
+#if !QT_CONFIG(temporaryfile)
if (error)
out.remove();
#else
@@ -867,6 +868,9 @@ QFile::copy(const QString &newName)
\include qfile-copy.qdocinc
+ \note On Android, this operation is not yet supported for \c content
+ scheme URIs.
+
\sa rename()
*/
@@ -886,7 +890,12 @@ 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.
+ On Android, it's expected to have access permission to the parent
+ of the file name, otherwise, it won't be possible to create this
+ non-existing file.
\sa QIODevice::OpenMode, setFileName()
*/
@@ -921,6 +930,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.
@@ -1130,6 +1184,8 @@ qint64 QFile::size() const
\since 6.0
Constructs a new file object to represent the file with the given \a name.
+
+ \include qfile.cpp qfile-explicit-constructor-note
*/
/*!
\fn QFile::QFile(const std::filesystem::path &name, QObject *parent)
@@ -1215,6 +1271,107 @@ qint64 QFile::size() const
*/
+/*!
+ \class QNtfsPermissionCheckGuard
+ \since 6.6
+ \inmodule QtCore
+ \brief The QNtfsPermissionCheckGuard class is a RAII class to manage NTFS
+ permission checking.
+
+ \ingroup io
+
+ For performance reasons, QFile, QFileInfo, and related classes do not
+ perform full ownership and permission (ACL) checking on NTFS file systems
+ by default. During the lifetime of any instance of this class, that
+ default is overridden and advanced checking is performed. This provides
+ a safe and easy way to manage enabling and disabling this change to the
+ default behavior.
+
+ Example:
+
+ \snippet ntfsp.cpp raii
+
+ This class is available only on Windows.
+
+ \section1 qt_ntfs_permission_lookup
+
+ Prior to Qt 6.6, the user had to directly manipulate the global variable
+ \c qt_ntfs_permission_lookup. However, this was a non-atomic global
+ variable and as such it was prone to data races.
+
+ The variable \c qt_ntfs_permission_lookup is therefore deprecated since Qt
+ 6.6.
+*/
+
+/*!
+ \fn QNtfsPermissionCheckGuard::QNtfsPermissionCheckGuard()
+
+ Creates a guard and calls the function qEnableNtfsPermissionChecks().
+*/
+
+/*!
+ \fn QNtfsPermissionCheckGuard::~QNtfsPermissionCheckGuard()
+
+ Destroys the guard and calls the function qDisableNtfsPermissionChecks().
+*/
+
+
+/*!
+ \fn bool qEnableNtfsPermissionChecks()
+ \since 6.6
+ \threadsafe
+ \relates QNtfsPermissionCheckGuard
+
+ Enables permission checking on NTFS file systems. Returns \c true if the check
+ was already enabled before the call to this function, meaning that there
+ are other users.
+
+ This function is only available on Windows and makes the direct
+ manipulation of \l qt_ntfs_permission_lookup obsolete.
+
+ This is a low-level function, please consider the RAII class
+ \l QNtfsPermissionCheckGuard instead.
+
+ \note The thread-safety of this function holds only as long as there are no
+ concurrent updates to \l qt_ntfs_permission_lookup.
+*/
+
+/*!
+ \fn bool qDisableNtfsPermissionChecks()
+ \since 6.6
+ \threadsafe
+ \relates QNtfsPermissionCheckGuard
+
+ Disables permission checking on NTFS file systems. Returns \c true if the
+ check is disabled, meaning that there are no more users.
+
+ This function is only available on Windows and makes the direct
+ manipulation of \l qt_ntfs_permission_lookup obsolete.
+
+ This is a low-level function and must (only) be called to match one earlier
+ call to qEnableNtfsPermissionChecks(). Please consider the RAII class
+ \l QNtfsPermissionCheckGuard instead.
+
+ \note The thread-safety of this function holds only as long as there are no
+ concurrent updates to \l qt_ntfs_permission_lookup.
+*/
+
+/*!
+ \fn bool qAreNtfsPermissionChecksEnabled()
+ \since 6.6
+ \threadsafe
+ \relates QNtfsPermissionCheckGuard
+
+ Checks the status of the permission checks on NTFS file systems. Returns
+ \c true if the check is enabled.
+
+ This function is only available on Windows and makes the direct
+ manipulation of \l qt_ntfs_permission_lookup obsolete.
+
+ \note The thread-safety of this function holds only as long as there are no
+ concurrent updates to \l qt_ntfs_permission_lookup.
+*/
+
QT_END_NAMESPACE
#ifndef QT_NO_QOBJECT