diff options
Diffstat (limited to 'src/corelib/io/qtemporaryfile.cpp')
-rw-r--r-- | src/corelib/io/qtemporaryfile.cpp | 157 |
1 files changed, 90 insertions, 67 deletions
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 4b587857a8..4e48a18d91 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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) 2016 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 "qtemporaryfile.h" @@ -59,6 +23,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + #if defined(Q_OS_WIN) typedef ushort Char; @@ -79,19 +45,19 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName) { // Ensure there is a placeholder mask QString qfilename = QDir::fromNativeSeparators(templateName); - uint phPos = qfilename.length(); - uint phLength = 0; + qsizetype phPos = qfilename.size(); + qsizetype phLength = 0; while (phPos != 0) { --phPos; - if (qfilename[phPos] == QLatin1Char('X')) { + if (qfilename[phPos] == u'X') { ++phLength; continue; } if (phLength >= 6 - || qfilename[phPos] == QLatin1Char('/')) { + || qfilename[phPos] == u'/') { ++phPos; break; } @@ -101,15 +67,14 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName) } if (phLength < 6) - qfilename.append(QLatin1String(".XXXXXX")); + qfilename.append(".XXXXXX"_L1); // "Nativify" :-) - QFileSystemEntry::NativePath filename = QFileSystemEngine::absoluteName( - QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath())) - .nativeFilePath(); + QFileSystemEntry::NativePath filename = + QFileSystemEntry(QDir::cleanPath(qfilename)).nativeFilePath(); // Find mask in native path - phPos = filename.length(); + phPos = filename.size(); phLength = 0; while (phPos != 0) { --phPos; @@ -143,8 +108,8 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName) QFileSystemEntry::NativePath QTemporaryFileName::generateNext() { Q_ASSERT(length != 0); - Q_ASSERT(pos < path.length()); - Q_ASSERT(length <= path.length() - pos); + Q_ASSERT(pos < path.size()); + Q_ASSERT(length <= path.size() - pos); Char *const placeholderStart = (Char *)path.data() + pos; Char *const placeholderEnd = placeholderStart + length; @@ -191,13 +156,13 @@ QFileSystemEntry::NativePath QTemporaryFileName::generateNext() return path; } -#ifndef QT_NO_TEMPORARYFILE +#if QT_CONFIG(temporaryfile) /*! \internal Generates a unique file path from the template \a templ and creates a new - file based based on those parameters: the \c templ.length characters in \c + file based on those parameters: the \c templ.length characters in \c templ.path starting at \c templ.pos will be replaced by a random sequence of characters. \a mode specifies the file mode bits (not used on Windows). @@ -219,8 +184,9 @@ static bool createFileFromTemplate(NativeFileHandle &file, QTemporaryFileName &t const DWORD shareMode = (flags & QTemporaryFileEngine::Win32NonShared) ? 0u : (FILE_SHARE_READ | FILE_SHARE_WRITE); + const DWORD extraAccessFlags = (flags & QTemporaryFileEngine::Win32NonShared) ? DELETE : 0; file = CreateFile((const wchar_t *)path.constData(), - GENERIC_READ | GENERIC_WRITE, + GENERIC_READ | GENERIC_WRITE | extraAccessFlags, shareMode, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); @@ -425,6 +391,18 @@ bool QTemporaryFileEngine::renameOverwrite(const QString &newName) QFSFileEngine::close(); return ok; } +#ifdef Q_OS_WIN + if (flags & Win32NonShared) { + QFileSystemEntry newEntry(newName, QFileSystemEntry::FromInternalPath()); + bool ok = d_func()->nativeRenameOverwrite(newEntry); + QFSFileEngine::close(); + if (ok) { + // Match what QFSFileEngine::renameOverwrite() does + setFileEntry(std::move(newEntry)); + } + return ok; + } +#endif QFSFileEngine::close(); return QFSFileEngine::renameOverwrite(newName); } @@ -440,7 +418,7 @@ bool QTemporaryFileEngine::close() QString QTemporaryFileEngine::fileName(QAbstractFileEngine::FileName file) const { if (isUnnamedFile()) { - if (file == AbsoluteLinkTarget) { + if (file == AbsoluteLinkTarget || file == RawLinkPath) { // we know our file isn't (won't be) a symlink return QString(); } @@ -576,9 +554,9 @@ QString QTemporaryFilePrivate::defaultTemplateName() baseName = QCoreApplication::applicationName(); if (baseName.isEmpty()) #endif - baseName = QLatin1String("qt_temp"); + baseName = "qt_temp"_L1; - return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String(".XXXXXX"); + return QDir::tempPath() + u'/' + baseName + ".XXXXXX"_L1; } //************* QTemporaryFile @@ -620,6 +598,9 @@ QString QTemporaryFilePrivate::defaultTemplateName() be placed into the temporary path as returned by QDir::tempPath(). If you specify your own filename, a relative file path will not be placed in the temporary directory by default, but be relative to the current working directory. + It is important to specify the correct directory if the rename() function will be + called, as QTemporaryFile can only rename files within the same volume / filesystem + as the temporary file itself was created on. Specified filenames can contain the following template \c XXXXXX (six upper case "X" characters), which will be replaced by the @@ -662,6 +643,12 @@ QTemporaryFile::QTemporaryFile() } /*! + \fn QTemporaryFile::QTemporaryFile(const std::filesystem::path &templateName, QObject *parent) + \overload + \since 6.7 +*/ + +/*! Constructs a QTemporaryFile with a template filename of \a templateName. Upon opening the temporary file this will be used to create a unique filename. @@ -671,7 +658,11 @@ QTemporaryFile::QTemporaryFile() If \a templateName is a relative path, the path will be relative to the current working directory. You can use QDir::tempPath() to construct \a - templateName if you want use the system's temporary directory. + templateName if you want use the system's temporary directory. It is + important to specify the correct directory if the rename() function will be + called, as QTemporaryFile can only rename files within the same volume / + filesystem as the temporary file itself was created on. + \sa open(), fileTemplate() */ @@ -704,7 +695,10 @@ QTemporaryFile::QTemporaryFile(QObject *parent) If \a templateName is a relative path, the path will be relative to the current working directory. You can use QDir::tempPath() to construct \a - templateName if you want use the system's temporary directory. + templateName if you want use the system's temporary directory. It is + important to specify the correct directory if the rename() function will be + called, as QTemporaryFile can only rename files within the same volume / + filesystem as the temporary file itself was created on. \sa open(), fileTemplate() */ @@ -737,7 +731,7 @@ QTemporaryFile::~QTemporaryFile() return true upon success and will set the fileName() to the unique filename used. - \sa fileName() + \sa fileName(), QT_USE_NODISCARD_FILE_OPEN */ /*! @@ -816,6 +810,12 @@ QString QTemporaryFile::fileTemplate() const } /*! + \fn void QTemporaryFile::setFileTemplate(const std::filesystem::path &name) + \overload + \since 6.7 +*/ + +/*! Sets the static portion of the file name to \a name. If the file template contains XXXXXX that will automatically be replaced with the unique part of the filename, otherwise a filename will be @@ -823,7 +823,10 @@ QString QTemporaryFile::fileTemplate() const If \a name contains a relative file path, the path will be relative to the current working directory. You can use QDir::tempPath() to construct \a - name if you want use the system's temporary directory. + name if you want use the system's temporary directory. It is important to + specify the correct directory if the rename() function will be called, as + QTemporaryFile can only rename files within the same volume / filesystem as + the temporary file itself was created on. \sa fileTemplate() */ @@ -834,11 +837,28 @@ void QTemporaryFile::setFileTemplate(const QString &name) } /*! - \internal + \fn bool QTemporaryFile::rename(const std::filesystem::path &newName) + \overload + \since 6.7 +*/ - This is just a simplified version of QFile::rename() because we know a few - extra details about what kind of file we have. The documentation is hidden - from the user because QFile::rename() should be enough. +/*! + Renames the current temporary file to \a newName and returns true if it + succeeded. + + This function has an important difference compared to QFile::rename(): it + will not perform a copy+delete if the low-level system call to rename the + file fails, something that could happen if \a newName specifies a file in a + different volume or filesystem than the temporary file was created on. In + other words, QTemporaryFile only supports atomic file renaming. + + This functionality is intended to support materializing the destination + file with all contents already present, so another process cannot see an + incomplete file in the process of being written. The \l QSaveFile class can + be used for a similar purpose too, particularly if the destination file is + not temporary. + + \sa QSaveFile, QSaveFile::commit(), QFile::rename() */ bool QTemporaryFile::rename(const QString &newName) { @@ -853,7 +873,6 @@ bool QTemporaryFile::rename(const QString &newName) if (tef->rename(newName)) { unsetError(); // engine was able to handle the new name so we just reset it - tef->setFileName(newName); d->fileName = newName; return true; } @@ -870,7 +889,11 @@ bool QTemporaryFile::rename(const QString &newName) Works on the given \a fileName rather than an existing QFile object. */ - +/*! + \fn QTemporaryFile *QTemporaryFile::createNativeFile(const std::filesystem::path &fileName) + \overload + \since 6.7 +*/ /*! If \a file is not already a native file, then a QTemporaryFile is created @@ -958,7 +981,7 @@ bool QTemporaryFile::open(OpenMode flags) return false; } -#endif // QT_NO_TEMPORARYFILE +#endif // QT_CONFIG(temporaryfile) QT_END_NAMESPACE |