QHash
QLibrary
QObjectCleanupHandler
- QAbstractFileEngine
QTranslator
QWaitCondition
QMimeData
${CMAKE_CURRENT_SOURCE_DIR}/global/qnamespace.h
${CMAKE_CURRENT_SOURCE_DIR}/global/qnumeric.h
${CMAKE_CURRENT_SOURCE_DIR}/global/qplatformdefs.h
- ${CMAKE_CURRENT_SOURCE_DIR}/io/qabstractfileengine.h
- ${CMAKE_CURRENT_SOURCE_DIR}/io/qabstractfileengine_p.h
${CMAKE_CURRENT_SOURCE_DIR}/io/qbuffer.h
${CMAKE_CURRENT_SOURCE_DIR}/io/qdatastream.h
${CMAKE_CURRENT_SOURCE_DIR}/io/qdataurl_p.h
${CMAKE_CURRENT_SOURCE_DIR}/global/qglobal.cpp
${CMAKE_CURRENT_SOURCE_DIR}/global/qlibraryinfo.cpp
${CMAKE_CURRENT_SOURCE_DIR}/global/qt_error_string.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/io/qabstractfileengine.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io/qbuffer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io/qdatastream.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io/qdataurl.cpp
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Copyright (C) 2016 Ivailo Monev
-**
-** This file is part of the QtCore module of the Katie Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-**
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qabstractfileengine.h"
-#include "qabstractfileengine_p.h"
-#include "qdatetime.h"
-#include "qdebug.h"
-#include "qfilesystementry_p.h"
-#include "qfilesystemengine_p.h"
-#include "qfileinfo_p.h"
-#include "qcore_unix_p.h"
-
-#include <sys/mman.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <errno.h>
-
-QT_BEGIN_NAMESPACE
-
-QAbstractFileEnginePrivate::QAbstractFileEnginePrivate()
- : fileError(QFile::UnspecifiedError),
- openMode(QIODevice::NotOpen),
- fd(-1),
- closeFileHandle(false)
-{
-}
-
-bool QAbstractFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const
-{
- if (!metaData.hasFlags(flags)) {
- if (!fileEntry.isEmpty())
- QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags));
-
- if (metaData.missingFlags(flags) && fd != -1)
- QFileSystemEngine::fillMetaData(fd, metaData);
- }
-
- return metaData.exists();
-}
-
-uchar *QAbstractFileEnginePrivate::map(qint64 offset, qint64 size)
-{
- Q_Q(QAbstractFileEngine);
- if (openMode == QIODevice::NotOpen) {
- q->setError(QFile::PermissionsError, qt_error_string(EACCES));
- return 0;
- }
-
- if (offset < 0 || offset != qint64(QT_OFF_T(offset))
- || size < 0 || quint64(size) > quint64(size_t(-1))) {
- q->setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
- return 0;
- }
-
- // If we know the mapping will extend beyond EOF, fail early to avoid
- // undefined behavior. Otherwise, let mmap have its say.
- if (doStat(QFileSystemMetaData::SizeAttribute)
- && (QT_OFF_T(size) > metaData.size() - QT_OFF_T(offset)))
- qWarning("QAbstractFileEngine::map: Mapping a file beyond its size is not portable");
-
- int access = 0;
- if (openMode & QIODevice::ReadOnly) access |= PROT_READ;
- if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE;
-
- static const int pageSize = ::getpagesize();
- const int extra = offset % pageSize;
-
- if (quint64(size + extra) > quint64((size_t)-1)) {
- q->setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
- return 0;
- }
-
- size_t realSize = (size_t)size + extra;
- QT_OFF_T realOffset = QT_OFF_T(offset);
- realOffset &= ~(QT_OFF_T(pageSize - 1));
-
- void *mapAddress = QT_MMAP(nullptr, realSize,
- access, MAP_SHARED, fd, realOffset);
- if (mapAddress != MAP_FAILED) {
- uchar *address = extra + static_cast<uchar*>(mapAddress);
- maps[address] = QPair<int,size_t>(extra, realSize);
- return address;
- }
-
- switch(errno) {
- case EBADF:
- q->setError(QFile::PermissionsError, qt_error_string(EACCES));
- break;
- case ENFILE:
- case ENOMEM:
- q->setError(QFile::ResourceError, qt_error_string(errno));
- break;
- case EINVAL:
- // size are out of bounds
- default:
- q->setError(QFile::UnspecifiedError, qt_error_string(errno));
- break;
- }
- return 0;
-}
-
-bool QAbstractFileEnginePrivate::unmap(uchar *ptr)
-{
- Q_Q(QAbstractFileEngine);
- if (!maps.contains(ptr)) {
- q->setError(QFile::PermissionsError, qt_error_string(EACCES));
- return false;
- }
-
- uchar *start = ptr - maps[ptr].first;
- size_t len = maps[ptr].second;
- if (::munmap(start, len) == -1) {
- q->setError(QFile::UnspecifiedError, qt_error_string(errno));
- return false;
- }
- maps.remove(ptr);
- return true;
-}
-
-/*!
- Creates and returns a QAbstractFileEngine suitable for processing \a
- fileName.
-*/
-QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
-{
- // fall back to regular file engine
- QAbstractFileEngine *engine = new QAbstractFileEngine();
- engine->d_ptr->fileEntry = QFileSystemEntry(fileName);
- return engine;
-}
-
-/*!
- \enum QAbstractFileEngine::FileName
-
- These values are used to request a file name in a particular
- format.
-
- \value DefaultName The same filename that was passed to the
- QAbstractFileEngine.
- \value BaseName The name of the file excluding the path.
- \value PathName The path to the file excluding the base name.
- \value AbsoluteName The absolute path to the file (including
- the base name).
- \value AbsolutePathName The absolute path to the file (excluding
- the base name).
- \value LinkName The full file name of the file that this file is a
- link to. (This will be empty if this file is not a link.)
- \value CanonicalName Often very similar to LinkName. Will return the true path to the file.
- \value CanonicalPathName Same as CanonicalName, excluding the base name.
-
- \omitvalue NFileNames
-
- \sa fileName(), setFileName()
-*/
-
-/*!
- \enum QAbstractFileEngine::FileTime
-
- These are used by the fileTime() function.
-
- \value CreationTime When the file was created.
- \value ModificationTime When the file was most recently modified.
- \value AccessTime When the file was most recently accessed (e.g.
- read or written to).
-
- \sa setFileName()
-*/
-
-/*!
- \enum QAbstractFileEngine::FileOwner
-
- \value OwnerUser The user who owns the file.
- \value OwnerGroup The group who owns the file.
-
- \sa owner(), ownerId(), setFileName()
-*/
-
-/*!
- Constructs a new QAbstractFileEngine that does not refer to any file or directory.
-
- \sa setFileName()
- */
-QAbstractFileEngine::QAbstractFileEngine()
- : d_ptr(new QAbstractFileEnginePrivate())
-{
- d_ptr->q_ptr = this;
-}
-
-/*!
- \internal
-
- Constructs a QAbstractFileEngine.
- */
-QAbstractFileEngine::QAbstractFileEngine(QAbstractFileEnginePrivate &dd)
- : d_ptr(&dd)
-{
- d_ptr->q_ptr = this;
-}
-
-/*!
- Destroys the QAbstractFileEngine.
- */
-QAbstractFileEngine::~QAbstractFileEngine()
-{
- Q_D(QAbstractFileEngine);
- if (d->closeFileHandle) {
- if (d->fd != -1) {
- qt_safe_close(d->fd);
- }
- }
- QList<uchar*> keys = d->maps.keys();
- for (int i = 0; i < keys.count(); ++i)
- unmap(keys.at(i));
-
- delete d_ptr;
-}
-
-/*!
- \fn bool QAbstractFileEngine::open(QIODevice::OpenMode mode)
-
- Opens the file in the specified \a mode. Returns true if the file
- was successfully opened; otherwise returns false.
-
- The \a mode is an OR combination of QIODevice::OpenMode and
- QIODevice::HandlingMode values.
-*/
-bool QAbstractFileEngine::open(QIODevice::OpenMode openMode)
-{
- Q_D(QAbstractFileEngine);
- if (Q_UNLIKELY(d->fileEntry.isEmpty())) {
- qWarning("QAbstractFileEngine::open: No file name specified");
- setError(QFile::OpenError, QLatin1String("No file name specified"));
- return false;
- }
-
- // Append implies WriteOnly.
- if (openMode & QFile::Append)
- openMode |= QFile::WriteOnly;
-
- // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
- if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
- openMode |= QFile::Truncate;
-
- d->openMode = openMode;
- d->metaData.clear();
- d->fd = -1;
-
- int flags = QT_OPEN_RDONLY;
-
- if ((d->openMode & QFile::ReadWrite) == QFile::ReadWrite) {
- flags = QT_OPEN_RDWR | QT_OPEN_CREAT;
- } else if (d->openMode & QFile::WriteOnly) {
- flags = QT_OPEN_WRONLY | QT_OPEN_CREAT;
- }
-
- if (d->openMode & QFile::Append) {
- flags |= QT_OPEN_APPEND;
- } else if (d->openMode & QFile::WriteOnly) {
- if ((d->openMode & QFile::Truncate) || !(d->openMode & QFile::ReadOnly))
- flags |= QT_OPEN_TRUNC;
- }
-
- if (d->openMode & QFile::Unbuffered) {
-#ifdef O_DSYNC
- flags |= O_DSYNC;
-#else
- flags |= O_SYNC;
-#endif
- }
-
- // Try to open the file.
- const QByteArray native = d->fileEntry.nativeFilePath();
- d->fd = qt_safe_open(native.constData(), flags, 0666);
-
- // On failure, return and report the error.
- if (d->fd == -1) {
- setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- qt_error_string(errno));
- d->openMode = QIODevice::NotOpen;
- return false;
- }
-
- // Refuse to open directories, EISDIR is not a thing (by standards) for
- // non-write modes.
- QT_STATBUF statbuf;
- if (QT_FSTAT(d->fd, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
- setError(QFile::OpenError, QLatin1String("file to open is a directory"));
- qt_safe_close(d->fd);
- d->openMode = QIODevice::NotOpen;
- d->fd = -1;
- return false;
- }
-
- // Seek to the end when in Append mode.
- if (d->openMode & QFile::Append) {
- if (QT_LSEEK(d->fd, 0, SEEK_END) == -1) {
- setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- qt_error_string(errno));
- qt_safe_close(d->fd);
- d->openMode = QIODevice::NotOpen;
- d->fd = -1;
- return false;
- }
- }
-
- d->closeFileHandle = true;
-
- return true;
-}
-
-/*!
- Closes the file, returning true if successful; otherwise returns false.
-
- The default implementation always returns false.
-*/
-bool QAbstractFileEngine::close()
-{
- Q_D(QAbstractFileEngine);
- d->openMode = QIODevice::NotOpen;
-
- if (d->fd == -1)
- return false;
-
- d->metaData.clear();
-
- // Close the file if we created the handle.
- if (d->closeFileHandle) {
- int ret = qt_safe_close(d->fd);
-
- // We must reset these guys regardless; calling close again after a
- // failed close causes crashes on some systems.
- d->fd = -1;
-
- // Report errors.
- if (ret != 0) {
- setError(QFile::UnspecifiedError, qt_error_string(errno));
- return false;
- }
- }
-
- return true;
-}
-
-/*!
- Flushes the open file, returning true if successful; otherwise returns
- false.
-
- The default implementation always returns false.
-*/
-bool QAbstractFileEngine::flush()
-{
- Q_D(const QAbstractFileEngine);
- return (d->fd != -1);
-}
-
-/*!
- Returns the size of the file.
-*/
-qint64 QAbstractFileEngine::size() const
-{
- Q_D(const QAbstractFileEngine);
-
- d->metaData.clear();
- if (!d->doStat(QFileSystemMetaData::SizeAttribute))
- return 0;
- return d->metaData.size();
-}
-
-/*!
- Returns the current file position.
-
- This is the position of the data read/write head of the file.
-*/
-qint64 QAbstractFileEngine::pos() const
-{
- Q_D(const QAbstractFileEngine);
- return (qint64)QT_LSEEK(d->fd, 0, SEEK_CUR);
-}
-
-/*!
- \fn bool QAbstractFileEngine::seek(qint64 offset)
-
- Sets the file position to the given \a offset. Returns true if
- the position was successfully set; otherwise returns false.
-
- The offset is from the beginning of the file, unless the
- file is sequential.
-
- \sa isSequential()
-*/
-bool QAbstractFileEngine::seek(qint64 pos)
-{
- Q_D(QAbstractFileEngine);
-
- if (pos < 0 || pos != qint64(QT_OFF_T(pos)))
- return false;
-
- if (Q_UNLIKELY(QT_LSEEK(d->fd, QT_OFF_T(pos), SEEK_SET) == -1)) {
- qWarning("QAbstractFileEngine::seek: Cannot set file position %lld", pos);
- setError(QFile::PositionError, qt_error_string(errno));
- return false;
- }
- return true;
-}
-
-/*!
- Returns true if the file is a sequential access device; returns
- false if the file is a direct access device.
-
- Operations involving size() and seek(int) are not valid on
- sequential devices.
-*/
-bool QAbstractFileEngine::isSequential() const
-{
- Q_D(const QAbstractFileEngine);
- if (d->doStat(QFileSystemMetaData::SequentialType))
- return d->metaData.isSequential();
- return true;
-}
-
-/*!
- Requests that the file is deleted from the file system. If the
- operation succeeds return true; otherwise return false.
-
- \sa setFileName() rmdir()
- */
-bool QAbstractFileEngine::remove()
-{
- Q_D(QAbstractFileEngine);
- int error;
- bool ret = QFileSystemEngine::removeFile(d->fileEntry, &error);
- d->metaData.clear();
- if (!ret) {
- setError(QFile::RemoveError, qt_error_string(error));
- }
- return ret;
-}
-
-/*!
- Copies the contents of this file to a file with the name \a newName.
- Returns true on success; otherwise, false is returned.
-*/
-bool QAbstractFileEngine::copy(const QString &newName)
-{
- Q_D(QAbstractFileEngine);
- int error;
- bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(newName), &error);
- if (!ret) {
- setError(QFile::CopyError, qt_error_string(error));
- }
- return ret;
-}
-
-/*!
- Requests that the file be renamed to \a newName in the file
- system. If the operation succeeds return true; otherwise return
- false.
-
- \sa setFileName()
- */
-bool QAbstractFileEngine::rename(const QString &newName)
-{
- Q_D(QAbstractFileEngine);
- int error;
- bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), &error);
- d->metaData.clear();
- if (!ret) {
- setError(QFile::RenameError, qt_error_string(error));
- }
-
- return ret;
-}
-
-/*!
- Creates a link from the file currently specified by fileName() to
- \a newName. What a link is depends on the underlying filesystem
- (be it a shortcut on Windows or a symbolic link on Unix). Returns
- true if successful; otherwise returns false.
-*/
-bool QAbstractFileEngine::link(const QString &newName)
-{
- Q_D(QAbstractFileEngine);
- int error;
- bool ret = QFileSystemEngine::createLink(d->fileEntry, QFileSystemEntry(newName), &error);
- if (!ret) {
- setError(QFile::RenameError, qt_error_string(error));
- }
- return ret;
-}
-
-/*!
- Requests that the file be set to size \a size. If \a size is larger
- than the current file then it is filled with 0's, if smaller it is
- simply truncated. If the operations succceeds return true; otherwise
- return false;
-
- \sa size()
-*/
-bool QAbstractFileEngine::setSize(qint64 size)
-{
- Q_D(QAbstractFileEngine);
- int ret = 0;
- if (d->fd != -1) {
- Q_EINTR_LOOP(ret, QT_FTRUNCATE(d->fd, size));
- } else {
- Q_EINTR_LOOP(ret, QT_TRUNCATE(d->fileEntry.nativeFilePath().constData(), size));
- }
- d->metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
- if (ret == -1) {
- setError(QFile::ResizeError, qt_error_string(errno));
- return false;
- }
- return true;
-}
-
-/*!
- Return true if the file referred to by this file engine has a
- relative path; otherwise return false.
-
- \sa setFileName()
-*/
-bool QAbstractFileEngine::isRelativePath() const
-{
- Q_D(const QAbstractFileEngine);
- return d->fileEntry.filePath().length() ? d->fileEntry.filePath()[0] != QLatin1Char('/') : true;
-}
-
-/*!
- Return true if the file referred to by this file engine exists;
- otherwise return false.
-*/
-bool QAbstractFileEngine::exists() const
-{
- Q_D(const QAbstractFileEngine);
- d->metaData.clear(); // always stat
- if (!d->doStat(QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::FileType))
- return false;
- return d->metaData.exists() && d->metaData.isFile();
-}
-
-/*!
- Return the set of permissions for the file engine's file.
-
- \sa setFileName()
-*/
-QFile::Permissions QAbstractFileEngine::permissions() const
-{
- Q_D(const QAbstractFileEngine);
- bool exists = d->doStat(QFileSystemMetaData::Permissions | QFileSystemMetaData::LinkType);
- if (!exists && !d->metaData.isLink())
- return 0;
- return d->metaData.permissions();
-}
-
-/*!
- Requests that the file's permissions be set to \a perms. The argument
- perms will be set to the OR-ed together combination of
- QAbstractFileEngine::FileInfo, with only the QAbstractFileEngine::PermsMask being
- honored. If the operations succceeds return true; otherwise return
- false;
-
- \sa size()
-*/
-bool QAbstractFileEngine::setPermissions(uint perms)
-{
- Q_D(QAbstractFileEngine);
- int error;
- if (!QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), &error)) {
- setError(QFile::PermissionsError, qt_error_string(error));
- return false;
- }
- return true;
-}
-
-/*!
- Return the file engine's current file name in the format
- specified by \a file.
-
- If you don't handle some \c FileName possibilities, return the
- file name set in setFileName() when an unhandled format is
- requested.
-
- \sa setFileName(), FileName
- */
-QString QAbstractFileEngine::fileName(FileName file) const
-{
- Q_D(const QAbstractFileEngine);
- if (file == BaseName) {
- return d->fileEntry.fileName();
- } else if (file == PathName) {
- return d->fileEntry.path();
- } else if (file == AbsoluteName || file == AbsolutePathName) {
- QFileSystemEntry entry(QFileSystemEngine::absoluteName(d->fileEntry));
- if (file == AbsolutePathName) {
- return entry.path();
- }
- return entry.filePath();
- } else if (file == CanonicalName || file == CanonicalPathName) {
- QFileSystemEntry entry(QFileSystemEngine::canonicalName(d->fileEntry, d->metaData));
- if (file == CanonicalPathName)
- return entry.path();
- return entry.filePath();
- } else if (file == LinkName) {
- if (!d->metaData.hasFlags(QFileSystemMetaData::LinkType))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::LinkType);
- if (d->metaData.isLink()) {
- QFileSystemEntry entry = QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData);
- return entry.filePath();
- }
- return QString();
- }
- return d->fileEntry.filePath();
-}
-
-/*!
- If \a owner is \c OwnerUser return the ID of the user who owns
- the file. If \a owner is \c OwnerGroup return the ID of the group
- that own the file. If you can't determine the owner return -2.
-
- \sa owner() setFileName(), FileOwner
- */
-uint QAbstractFileEngine::ownerId(FileOwner owner) const
-{
- Q_D(const QAbstractFileEngine);
-
- if (d->doStat(QFileSystemMetaData::OwnerIds)) {
- if (owner == QAbstractFileEngine::OwnerUser)
- return d->metaData.userId();
- return d->metaData.groupId();
- }
-
- return QFileSystemMetaData::nobodyID;
-}
-
-/*!
- If \a owner is \c OwnerUser return the name of the user who owns
- the file. If \a owner is \c OwnerGroup return the name of the group
- that own the file. If you can't determine the owner return
- QString().
-
- \sa ownerId() setFileName(), FileOwner
- */
-QString QAbstractFileEngine::owner(FileOwner owner) const
-{
- if (owner == QAbstractFileEngine::OwnerUser)
- return QFileSystemEngine::resolveUserName(ownerId(owner));
- return QFileSystemEngine::resolveGroupName(ownerId(owner));
-}
-
-/*!
- If \a time is \c CreationTime, return when the file was created.
- If \a time is \c ModificationTime, return when the file was most
- recently modified. If \a time is \c AccessTime, return when the
- file was most recently accessed (e.g. read or written).
- If the time cannot be determined return QDateTime() (an invalid
- date time).
-
- \sa setFileName(), QDateTime, QDateTime::isValid(), FileTime
- */
-QDateTime QAbstractFileEngine::fileTime(FileTime time) const
-{
- Q_D(const QAbstractFileEngine);
-
- if (d->doStat(QFileSystemMetaData::Times)) {
- switch (time) {
- case QAbstractFileEngine::ModificationTime:
- return d->metaData.modificationTime();
- case QAbstractFileEngine::AccessTime:
- return d->metaData.accessTime();
- case QAbstractFileEngine::CreationTime:
- return d->metaData.creationTime();
- }
- }
-
- return QDateTime();
-}
-
-/*!
- Sets the file engine's file name to \a file. This file name is the
- file that the rest of the functions will operate on.
-
- \sa rename()
- */
-void QAbstractFileEngine::setFileName(const QString &file)
-{
- Q_D(QAbstractFileEngine);
- d->metaData.clear();
- d->openMode = QIODevice::NotOpen;
- d->fd = -1;
- d->closeFileHandle = false;
- d->fileEntry = QFileSystemEntry(file);
-}
-
-/*!
- Returns the native file handle for this file engine. This handle must be
- used with care; its value and type are platform specific, and using it
- will most likely lead to non-portable code.
-*/
-int QAbstractFileEngine::handle() const
-{
- Q_D(const QAbstractFileEngine);
- return d->fd;
-}
-
-/*!
- \since 4.4
-
- Maps \a size bytes of the file into memory starting at \a offset.
- Returns a pointer to the memory if successful; otherwise returns false
- if, for example, an error occurs.
-
- \sa unmap(), supportsExtension()
- */
-
-uchar *QAbstractFileEngine::map(qint64 offset, qint64 size)
-{
- MapExtensionOption option;
- option.offset = offset;
- option.size = size;
- MapExtensionReturn r;
- if (!extension(MapExtension, &option, &r))
- return 0;
- return r.address;
-}
-
-/*!
- \since 4.4
-
- Unmaps the memory \a address. Returns true if the unmap succeeds; otherwise
- returns false.
-
- \sa map(), supportsExtension()
- */
-bool QAbstractFileEngine::unmap(uchar *address)
-{
- UnMapExtensionOption options;
- options.address = address;
- return extension(UnMapExtension, &options);
-}
-
-/*!
- Reads a number of characters from the file into \a data. At most
- \a maxlen characters will be read.
-
- Returns -1 if a fatal error occurs, or 0 if there are no bytes to
- read.
-*/
-qint64 QAbstractFileEngine::read(char *data, qint64 maxlen)
-{
- Q_D(QAbstractFileEngine);
-
- if (maxlen < 0) {
- setError(QFile::ReadError, qt_error_string(EINVAL));
- return -1;
- }
-
- qint64 readBytes = 0;
- bool eof = false;
-
- if (d->fd != -1) {
- ssize_t result;
- do {
- result = QT_READ(d->fd, data + readBytes, size_t(maxlen - readBytes));
- } while ((result == -1 && errno == EINTR)
- || (result > 0 && (readBytes += result) < maxlen));
-
- eof = !(result == -1);
- }
-
- if (!eof && readBytes == 0) {
- readBytes = -1;
- setError(QFile::ReadError, qt_error_string(errno));
- }
-
- return readBytes;
-}
-
-/*!
- Writes \a len bytes from \a data to the file. Returns the number
- of characters written on success; otherwise returns -1.
-*/
-qint64 QAbstractFileEngine::write(const char *data, qint64 len)
-{
- Q_D(QAbstractFileEngine);
-
- if (len < 0 || len != qint64(size_t(len))) {
- setError(QFile::WriteError, qt_error_string(EINVAL));
- return -1;
- }
-
- qint64 writtenBytes = 0;
-
- if (d->fd != -1) {
- ssize_t result;
- do {
- result = QT_WRITE(d->fd, data + writtenBytes, size_t(len - writtenBytes));
- } while ((result == -1 && errno == EINTR)
- || (result > 0 && (writtenBytes += result) < len));
- }
-
- if (len && writtenBytes == 0) {
- writtenBytes = -1;
- setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno));
- }
-
- d->metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
-
- return writtenBytes;
-}
-
-/*!
- Reads one line, terminated by a '\n' character, from the file info
- \a data. At most \a maxlen characters will be read. The end-of-line
- character is included.
-*/
-qint64 QAbstractFileEngine::readLine(char *data, qint64 maxlen)
-{
- qint64 readSoFar = 0;
- while (readSoFar < maxlen) {
- char c;
- qint64 readResult = read(&c, 1);
- if (readResult <= 0)
- return (readSoFar > 0) ? readSoFar : -1;
- ++readSoFar;
- *data++ = c;
- if (c == '\n')
- return readSoFar;
- }
- return readSoFar;
-}
-
-/*!
- \enum QAbstractFileEngine::Extension
- \since 4.3
-
- This enum describes the types of extensions that the file engine can
- support. Before using these extensions, you must verify that the extension
- is supported (i.e., call supportsExtension()).
-
- \value FastReadLineExtension Whether the file engine provides a
- fast implementation for readLine() or not. If readLine() remains
- unimplemented in the file engine, QAbstractFileEngine will provide
- an implementation based on calling read() repeatedly. If
- supportsExtension() returns false for this extension, however,
- QIODevice can provide a faster implementation by making use of its
- internal buffer. For engines that already provide a fast readLine()
- implementation, returning false for this extension can avoid
- unnnecessary double-buffering in QIODevice.
-
- \value MapExtension Whether the file engine provides the ability to map
- a file to memory.
-
- \value UnMapExtension Whether the file engine provides the ability to
- unmap memory that was previously mapped.
-*/
-
-/*!
- \class QAbstractFileEngine::ExtensionOption
- \since 4.3
- \brief provides an extended input argument to QAbstractFileEngine's
- extension support.
-
- \sa QAbstractFileEngine::extension()
-*/
-
-/*!
- \class QAbstractFileEngine::ExtensionReturn
- \since 4.3
- \brief provides an extended output argument to QAbstractFileEngine's
- extension support.
-
- \sa QAbstractFileEngine::extension()
-*/
-
-/*!
- \since 4.3
-
- The \a option argument is provided as input to the extension, and
- this function can store output results in \a output.
-
- The behavior of this function is determined by \a extension; see the
- Extension documentation for details.
-
- You can call supportsExtension() to check if an extension is supported by
- the file engine.
-
- By default, map and unmap extensions are supported.
-
- \sa supportsExtension(), Extension
-*/
-bool QAbstractFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
-{
- Q_D(QAbstractFileEngine);
-
- if (extension == MapExtension) {
- const MapExtensionOption *options = (MapExtensionOption*)(option);
- MapExtensionReturn *returnValue = static_cast<MapExtensionReturn*>(output);
- returnValue->address = d->map(options->offset, options->size);
- return (returnValue->address != 0);
- } else if (extension == UnMapExtension) {
- UnMapExtensionOption *options = (UnMapExtensionOption*)option;
- return d->unmap(options->address);
- }
-
- return false;
-}
-
-/*!
- \since 4.3
-
- Returns true if the file engine supports \a extension; otherwise, false
- is returned. By default map, unmap and fast readline extensions are supported.
-
- \sa extension()
-*/
-bool QAbstractFileEngine::supportsExtension(Extension extension) const
-{
- Q_D(const QAbstractFileEngine);
- if (extension == FastReadLineExtension && d->fd != -1 && isSequential())
- return true;
- if (extension == UnMapExtension || extension == MapExtension)
- return true;
- return false;
-}
-
-/*!
- Returns the QFile::FileError that resulted from the last failed
- operation. If QFile::UnspecifiedError is returned, QFile will
- use its own idea of the error status.
-
- \sa QFile::FileError, errorString()
- */
-QFile::FileError QAbstractFileEngine::error() const
-{
- Q_D(const QAbstractFileEngine);
- return d->fileError;
-}
-
-/*!
- Returns the human-readable message appropriate to the current error
- reported by error(). If no suitable string is available, an
- empty string is returned.
-
- \sa error()
- */
-QString QAbstractFileEngine::errorString() const
-{
- Q_D(const QAbstractFileEngine);
- return d->errorString;
-}
-
-/*!
- Sets the error type to \a error, and the error string to \a errorString.
-
- \sa QFile::error(), QIODevice::errorString(), QIODevice::setErrorString()
-*/
-void QAbstractFileEngine::setError(QFile::FileError error, const QString &errorString)
-{
- Q_D(QAbstractFileEngine);
- d->fileError = error;
- d->errorString = errorString;
-}
-
-/*!
- Opens the file descriptor \a fd in \a openMode mode. Returns true
- on success; otherwise returns false.
-
- The \a handleFlags argument specifies whether the file handle will be
- closed by Katie. See the QFile::FileHandleFlags documentation for more
- information.
-*/
-bool QAbstractFileEngine::open(QIODevice::OpenMode openMode, int fd, QFile::FileHandleFlags handleFlags)
-{
- Q_D(QAbstractFileEngine);
-
- // Append implies WriteOnly.
- if (openMode & QFile::Append)
- openMode |= QFile::WriteOnly;
-
- // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
- if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
- openMode |= QFile::Truncate;
-
- d->openMode = openMode;
- d->closeFileHandle = (handleFlags & QFile::AutoCloseHandle);
- d->fileEntry.clear();
- d->fd = fd;
- d->metaData.clear();
-
- // Seek to the end when in Append mode.
- if (d->openMode & QFile::Append) {
- if (QT_LSEEK(d->fd, 0, SEEK_END) == -1) {
- setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- qt_error_string(errno));
- if (d->closeFileHandle) {
- qt_safe_close(d->fd);
- }
- d->openMode = QIODevice::NotOpen;
- d->fd = -1;
- return false;
- }
- }
-
- return true;
-}
-
-QT_END_NAMESPACE
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Copyright (C) 2016 Ivailo Monev
-**
-** This file is part of the QtCore module of the Katie Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-**
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QABSTRACTFILEENGINE_H
-#define QABSTRACTFILEENGINE_H
-
-#include <QtCore/qfile.h>
-#include <QtCore/qdatetime.h>
-
-#ifdef open
-#error qabstractfileengine.h must be included before any header file that defines open
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QAbstractFileEnginePrivate;
-
-class Q_CORE_EXPORT QAbstractFileEngine
-{
-public:
- enum FileName {
- DefaultName,
- BaseName,
- PathName,
- AbsoluteName,
- AbsolutePathName,
- LinkName,
- CanonicalName,
- CanonicalPathName,
- NFileNames
- };
- enum FileOwner {
- OwnerUser,
- OwnerGroup
- };
- enum FileTime {
- CreationTime,
- ModificationTime,
- AccessTime
- };
-
- ~QAbstractFileEngine();
-
- virtual bool open(QIODevice::OpenMode openMode); // virtual for QTemporaryFile
- virtual bool close(); // virtual for QTemporaryFile
- bool flush();
- qint64 size() const;
- qint64 pos() const;
- bool seek(qint64 pos);
- bool isSequential() const;
- virtual bool remove(); // virtual for QTemporaryFile
- bool copy(const QString &newName);
- virtual bool rename(const QString &newName); // virtual for QTemporaryFile
- bool link(const QString &newName);
- bool setSize(qint64 size);
- bool isRelativePath() const;
- bool exists() const;
- QFile::Permissions permissions() const;
- bool setPermissions(uint perms);
- QString fileName(FileName file) const;
- uint ownerId(FileOwner) const;
- QString owner(FileOwner) const;
- QDateTime fileTime(FileTime time) const;
- virtual void setFileName(const QString &file); // virtual for QTemporaryFile
- int handle() const;
- uchar *map(qint64 offset, qint64 size);
- bool unmap(uchar *ptr);
-
- qint64 read(char *data, qint64 maxlen);
- qint64 readLine(char *data, qint64 maxlen);
- qint64 write(const char *data, qint64 len);
-
- QFile::FileError error() const;
- QString errorString() const;
-
- enum Extension {
- FastReadLineExtension,
- MapExtension,
- UnMapExtension
- };
- class ExtensionOption
- {};
- class ExtensionReturn
- {};
-
- class MapExtensionOption : public ExtensionOption {
- public:
- qint64 offset;
- qint64 size;
- };
- class MapExtensionReturn : public ExtensionReturn {
- public:
- uchar *address;
- };
-
- class UnMapExtensionOption : public ExtensionOption {
- public:
- uchar *address;
- };
-
- bool extension(Extension extension, const ExtensionOption *option = nullptr, ExtensionReturn *output = nullptr);
- bool supportsExtension(Extension extension) const;
-
- // Factory
- static QAbstractFileEngine *create(const QString &fileName);
-
- //FS only!!
- bool open(QIODevice::OpenMode flags, int fd, QFile::FileHandleFlags handleFlags);
-
-protected:
- void setError(QFile::FileError error, const QString &str);
-
- QAbstractFileEngine();
- QAbstractFileEngine(QAbstractFileEnginePrivate &);
-
- QAbstractFileEnginePrivate* d_ptr;
-private:
- Q_DECLARE_PRIVATE(QAbstractFileEngine)
- Q_DISABLE_COPY(QAbstractFileEngine)
-
- friend class QFilePrivate;
-};
-
-QT_END_NAMESPACE
-
-#endif // QABSTRACTFILEENGINE_H
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Copyright (C) 2016 Ivailo Monev
-**
-** This file is part of the QtCore module of the Katie Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-**
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QABSTRACTFILEENGINE_P_H
-#define QABSTRACTFILEENGINE_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Katie API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "QtCore/qabstractfileengine.h"
-#include "qfilesystementry_p.h"
-#include "qfilesystemmetadata_p.h"
-#include "qhash.h"
-
-QT_BEGIN_NAMESPACE
-
-class QAbstractFileEnginePrivate
-{
-public:
- QAbstractFileEnginePrivate();
-
- QFile::FileError fileError;
- QString errorString;
-
- QFileSystemEntry fileEntry;
- QIODevice::OpenMode openMode;
-
- uchar *map(qint64 offset, qint64 size);
- bool unmap(uchar *ptr);
-
- mutable QFileSystemMetaData metaData;
-
- QHash<uchar *, QPair<int /*offset % PageSize*/, size_t /*length + offset % PageSize*/> > maps;
- int fd;
-
- bool closeFileHandle;
-
- bool doStat(QFileSystemMetaData::MetaDataFlags flags) const;
-
- QAbstractFileEngine *q_ptr;
- Q_DECLARE_PUBLIC(QAbstractFileEngine)
-};
-
-QT_END_NAMESPACE
-
-#endif // QABSTRACTFILEENGINE_P_H
#include "qfileinfo.h"
#include "qiodevice_p.h"
#include "qfile_p.h"
+#include "qfilesystemengine_p.h"
#include "qcorecommon_p.h"
+#include "qcore_unix_p.h"
#ifdef QT_NO_QOBJECT
#define tr(X) QString::fromLatin1(X)
#endif
+#include <sys/mman.h>
+
QT_BEGIN_NAMESPACE
//************* QFilePrivate
QFilePrivate::QFilePrivate()
- : fileEngine(0),
- error(QFile::NoError)
+ : error(QFile::NoError),
+ fd(-1),
+ closeFileHandle(false)
{
}
QFilePrivate::~QFilePrivate()
{
- delete fileEngine;
- fileEngine = 0;
}
-bool
-QFilePrivate::openExternalFile(int flags, int fd, QFile::FileHandleFlags handleFlags)
+bool QFilePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const
{
- delete fileEngine;
- fileEngine = 0;
- fileEngine = new QAbstractFileEngine();
- return fileEngine->open(QIODevice::OpenMode(flags), fd, handleFlags);
+ if (!metaData.hasFlags(flags)) {
+ if (!fileEntry.isEmpty())
+ QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags));
+
+ if (metaData.missingFlags(flags) && fd != -1)
+ QFileSystemEngine::fillMetaData(fd, metaData);
+ }
+
+ return metaData.exists();
}
-void
-QFilePrivate::setError(QFile::FileError err)
+bool QFilePrivate::unmap(uchar *ptr)
{
- error = err;
- errorString.clear();
+ if (!maps.contains(ptr)) {
+ setError(QFile::PermissionsError, qt_error_string(EACCES));
+ return false;
+ }
+
+ uchar *start = ptr - maps[ptr].first;
+ size_t len = maps[ptr].second;
+ if (::munmap(start, len) == -1) {
+ setError(QFile::UnspecifiedError, qt_error_string(errno));
+ return false;
+ }
+ maps.remove(ptr);
+ return true;
+}
+
+bool QFilePrivate::openExternalFile(QIODevice::OpenMode mode, int _fd, QFile::FileHandleFlags handleFlags)
+{
+ // Append implies WriteOnly.
+ if (mode & QFile::Append)
+ mode |= QFile::WriteOnly;
+
+ // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
+ if ((mode & QFile::WriteOnly) && !(mode & (QFile::ReadOnly | QFile::Append)))
+ mode |= QFile::Truncate;
+
+ closeFileHandle = (handleFlags & QFile::AutoCloseHandle);
+ fileEntry.clear();
+ fd = _fd;
+ metaData.clear();
+
+ // Seek to the end when in Append mode.
+ if (mode & QFile::Append) {
+ if (QT_LSEEK(fd, 0, SEEK_END) == -1) {
+ setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
+ qt_error_string(errno));
+ if (closeFileHandle) {
+ qt_safe_close(fd);
+ }
+ fd = -1;
+ return false;
+ }
+ }
+
+ return true;
}
-void
-QFilePrivate::setError(QFile::FileError err, const QString &errStr)
+void QFilePrivate::setError(QFile::FileError err, const QString &errStr)
{
error = err;
errorString = errStr;
QFile::QFile(const QString &name)
: QIODevice(*new QFilePrivate)
{
- d_func()->fileName = name;
+ d_func()->fileEntry = QFileSystemEntry(name);
}
QFile::QFile(QFilePrivate &dd)
: QIODevice(dd)
: QIODevice(*new QFilePrivate, 0)
{
Q_D(QFile);
- d->fileName = name;
+ d->fileEntry = QFileSystemEntry(name);
}
/*!
Constructs a new file object with the given \a parent to represent the
: QIODevice(*new QFilePrivate, parent)
{
Q_D(QFile);
- d->fileName = name;
+ d->fileEntry = QFileSystemEntry(name);
}
/*!
\internal
*/
QString QFile::fileName() const
{
- return fileEngine()->fileName(QAbstractFileEngine::DefaultName);
+ Q_D(const QFile);
+ return d->fileEntry.filePath();
}
/*!
\sa fileName(), QFileInfo, QDir
*/
-void
-QFile::setFileName(const QString &name)
+void QFile::setFileName(const QString &name)
{
Q_D(QFile);
if (Q_UNLIKELY(isOpen())) {
qWarning("QFile::setFileName: File (%s) is already opened",
qPrintable(fileName()));
- close();
- }
- if(d->fileEngine) { //get a new file engine later
- delete d->fileEngine;
- d->fileEngine = 0;
}
- d->fileName = name;
+ close();
+ d->fileEntry = QFileSystemEntry(name);
}
/*!
\sa setDecodingFunction(), encodeName()
*/
-QString
-QFile::decodeName(const QByteArray &localFileName)
+QString QFile::decodeName(const QByteArray &localFileName)
{
return QString::fromLocal8Bit(localFileName.constData());
}
\sa fileName(), setFileName()
*/
-bool
-QFile::exists() const
+bool QFile::exists() const
{
- return fileEngine()->exists();
+ Q_D(const QFile);
+ d->metaData.clear(); // always stat
+ if (!d->doStat(QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::FileType))
+ return false;
+ return d->metaData.exists() && d->metaData.isFile();
}
/*!
returns false.
*/
-bool
-QFile::exists(const QString &fileName)
+bool QFile::exists(const QString &fileName)
{
QFileInfo info(fileName);
return (info.exists() && info.isFile());
\sa fileName() setFileName()
*/
-QString
-QFile::readLink() const
+QString QFile::readLink() const
{
- return fileEngine()->fileName(QAbstractFileEngine::LinkName);
+ Q_D(const QFile);
+ if (!d->metaData.hasFlags(QFileSystemMetaData::LinkType))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::LinkType);
+ if (d->metaData.isLink()) {
+ QFileSystemEntry entry = QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData);
+ return entry.filePath();
+ }
+ return QString();
}
/*!
QFile::exists() returns true if the symlink points to an existing file.
*/
-QString
-QFile::readLink(const QString &fileName)
+QString QFile::readLink(const QString &fileName)
{
return QFileInfo(fileName).readLink();
}
\sa setFileName()
*/
-bool
-QFile::remove()
+bool QFile::remove()
{
Q_D(QFile);
- if (Q_UNLIKELY(d->fileName.isEmpty())) {
+ if (Q_UNLIKELY(d->fileEntry.isEmpty())) {
qWarning("QFile::remove: Empty or null file name");
return false;
}
unsetError();
close();
if(error() == QFile::NoError) {
- if(fileEngine()->remove()) {
- unsetError();
- return true;
+ int error = 0;
+ bool ret = QFileSystemEngine::removeFile(d->fileEntry, &error);
+ d->metaData.clear();
+ if (!ret) {
+ d->setError(QFile::RemoveError, qt_error_string(error));
+ return false;
}
- d->setError(QFile::RemoveError, d->fileEngine->errorString());
+ unsetError();
+ return true;
}
return false;
}
QFile::rename(const QString &newName)
{
Q_D(QFile);
- if (Q_UNLIKELY(d->fileName.isEmpty())) {
+ if (Q_UNLIKELY(d->fileEntry.isEmpty())) {
qWarning("QFile::rename: Empty or null file name");
return false;
}
unsetError();
close();
if(error() == QFile::NoError) {
- if (fileEngine()->rename(newName)) {
- unsetError();
- // engine was able to handle the new name so we just reset it
- d->fileEngine->setFileName(newName);
- d->fileName = newName;
- return true;
+ int error = 0;
+ bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), &error);
+ d->metaData.clear();
+ if (!ret) {
+ d->setError(QFile::RenameError, qt_error_string(error));
+ return false;
}
- d->setError(QFile::RenameError, d->fileEngine->errorString());
+
+ unsetError();
+ // just reset it
+ d->metaData.clear();
+ d->fd = -1;
+ d->closeFileHandle = false;
+ d->fileEntry = QFileSystemEntry(newName);
+ return true;
}
return false;
}
\sa setFileName()
*/
-bool
-QFile::link(const QString &linkName)
+bool QFile::link(const QString &linkName)
{
Q_D(QFile);
- if (Q_UNLIKELY(d->fileName.isEmpty())) {
+ if (Q_UNLIKELY(d->fileEntry.isEmpty())) {
qWarning("QFile::link: Empty or null file name");
return false;
}
QFileInfo fi(linkName);
- if(fileEngine()->link(fi.absoluteFilePath())) {
- unsetError();
- return true;
+ int error = 0;
+ bool ret = QFileSystemEngine::createLink(d->fileEntry, QFileSystemEntry(fi.absoluteFilePath()), &error);
+ if (!ret) {
+ d->setError(QFile::RenameError, qt_error_string(error));
+ return false;
}
- d->setError(QFile::RenameError, d->fileEngine->errorString());
- return false;
+ unsetError();
+ return true;
}
/*!
QFile::copy(const QString &newName)
{
Q_D(QFile);
- if (Q_UNLIKELY(d->fileName.isEmpty())) {
+ if (Q_UNLIKELY(d->fileEntry.isEmpty())) {
qWarning("QFile::copy: Empty or null file name");
return false;
}
unsetError();
close();
if(error() == QFile::NoError) {
- if(fileEngine()->copy(newName)) {
+ int error = 0;
+ if(QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(newName), &error)) {
unsetError();
return true;
}
- d->setError(QFile::CopyError, d->fileEngine->errorString());
+ d->setError(QFile::CopyError, qt_error_string(error));
}
return false;
}
bool QFile::isSequential() const
{
Q_D(const QFile);
- return d->fileEngine && d->fileEngine->isSequential();
+ if (d->doStat(QFileSystemMetaData::SequentialType))
+ return d->metaData.isSequential();
+ return true;
}
/*!
unsetError();
if (Q_UNLIKELY((mode & (ReadOnly | WriteOnly)) == 0)) {
- qWarning("QIODevice::open: File access not specified");
+ qWarning("QFile::open: File access not specified");
return false;
}
- if (fileEngine()->open(mode)) {
- QIODevice::open(mode);
- return true;
+ if (Q_UNLIKELY(d->fileEntry.isEmpty())) {
+ qWarning("QFile::open: No file name specified");
+ d->setError(QFile::OpenError, QLatin1String("No file name specified"));
+ return false;
}
- QFile::FileError err = d->fileEngine->error();
- if(err == QFile::UnspecifiedError)
- err = QFile::OpenError;
- d->setError(err, d->fileEngine->errorString());
- return false;
+
+ // Append implies WriteOnly.
+ if (mode & QFile::Append)
+ mode |= QFile::WriteOnly;
+
+ // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
+ if ((mode & QFile::WriteOnly) && !(mode & (QFile::ReadOnly | QFile::Append)))
+ mode |= QFile::Truncate;
+
+ d->metaData.clear();
+ d->fd = -1;
+
+ int flags = QT_OPEN_RDONLY;
+
+ if ((mode & QFile::ReadWrite) == QFile::ReadWrite) {
+ flags = QT_OPEN_RDWR | QT_OPEN_CREAT;
+ } else if (mode & QFile::WriteOnly) {
+ flags = QT_OPEN_WRONLY | QT_OPEN_CREAT;
+ }
+
+ if (mode & QFile::Append) {
+ flags |= QT_OPEN_APPEND;
+ } else if (mode & QFile::WriteOnly) {
+ if ((mode & QFile::Truncate) || !(mode & QFile::ReadOnly))
+ flags |= QT_OPEN_TRUNC;
+ }
+
+ if (mode & QFile::Unbuffered) {
+#ifdef O_DSYNC
+ flags |= O_DSYNC;
+#else
+ flags |= O_SYNC;
+#endif
+ }
+
+ // Try to open the file.
+ const QByteArray native = d->fileEntry.nativeFilePath();
+ d->fd = qt_safe_open(native.constData(), flags, 0666);
+
+ // On failure, return and report the error.
+ if (d->fd == -1) {
+ d->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
+ qt_error_string(errno));
+ return false;
+ }
+
+ // Refuse to open directories, EISDIR is not a thing (by standards) for
+ // non-write modes.
+ QT_STATBUF statbuf;
+ if (QT_FSTAT(d->fd, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
+ qt_safe_close(d->fd);
+ d->fd = -1;
+ d->setError(QFile::OpenError, QLatin1String("file to open is a directory"));
+ return false;
+ }
+
+ // Seek to the end when in Append mode.
+ if (mode & QFile::Append) {
+ if (QT_LSEEK(d->fd, 0, SEEK_END) == -1) {
+ qt_safe_close(d->fd);
+ d->fd = -1;
+ d->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
+ qt_error_string(errno));
+ return false;
+ }
+ }
+
+ d->closeFileHandle = true;
+
+ QIODevice::open(mode);
+ return true;
}
/*! \fn QFile::open(OpenMode, FILE*)
int QFile::handle() const
{
Q_D(const QFile);
- if (!isOpen() || !d->fileEngine)
+ if (!isOpen())
return -1;
- return d->fileEngine->handle();
+ return d->fd;
}
/*!
Returns a pointer to the memory or 0 if there is an error.
- \sa unmap(), QAbstractFileEngine::supportsExtension()
+ \sa unmap()
*/
uchar *QFile::map(qint64 offset, qint64 size)
{
Q_D(QFile);
- if (fileEngine()
- && d->fileEngine->supportsExtension(QAbstractFileEngine::MapExtension)) {
- unsetError();
- uchar *address = d->fileEngine->map(offset, size);
- if (address == 0)
- d->setError(d->fileEngine->error(), d->fileEngine->errorString());
+ unsetError();
+ if (openMode() == QIODevice::NotOpen) {
+ d->setError(QFile::PermissionsError, qt_error_string(EACCES));
+ return 0;
+ }
+
+ if (offset < 0 || offset != qint64(QT_OFF_T(offset))
+ || size < 0 || quint64(size) > quint64(size_t(-1))) {
+ d->setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
+ return 0;
+ }
+
+ // If we know the mapping will extend beyond EOF, fail early to avoid
+ // undefined behavior. Otherwise, let mmap have its say.
+ if (d->doStat(QFileSystemMetaData::SizeAttribute)
+ && (QT_OFF_T(size) > d->metaData.size() - QT_OFF_T(offset)))
+ qWarning("QFile::map: Mapping a file beyond its size is not portable");
+
+ int access = 0;
+ if (openMode() & QIODevice::ReadOnly) access |= PROT_READ;
+ if (openMode() & QIODevice::WriteOnly) access |= PROT_WRITE;
+
+ static const int pageSize = ::getpagesize();
+ const int extra = offset % pageSize;
+
+ if (quint64(size + extra) > quint64((size_t)-1)) {
+ d->setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
+ return 0;
+ }
+
+ size_t realSize = (size_t)size + extra;
+ QT_OFF_T realOffset = QT_OFF_T(offset);
+ realOffset &= ~(QT_OFF_T(pageSize - 1));
+
+ void *mapAddress = QT_MMAP(nullptr, realSize,
+ access, MAP_SHARED, d->fd, realOffset);
+ if (mapAddress != MAP_FAILED) {
+ uchar *address = extra + static_cast<uchar*>(mapAddress);
+ d->maps[address] = QPair<int,size_t>(extra, realSize);
return address;
}
+
+ switch(errno) {
+ case EBADF:
+ d->setError(QFile::PermissionsError, qt_error_string(EACCES));
+ break;
+ case ENFILE:
+ case ENOMEM:
+ d->setError(QFile::ResourceError, qt_error_string(errno));
+ break;
+ case EINVAL:
+ // size are out of bounds
+ default:
+ d->setError(QFile::UnspecifiedError, qt_error_string(errno));
+ break;
+ }
return 0;
}
Returns true if the unmap succeeds; false otherwise.
- \sa map(), QAbstractFileEngine::supportsExtension()
+ \sa map()
*/
bool QFile::unmap(uchar *address)
{
Q_D(QFile);
- if (fileEngine()
- && d->fileEngine->supportsExtension(QAbstractFileEngine::UnMapExtension)) {
- unsetError();
- const bool success = d->fileEngine->unmap(address);
- if (!success)
- d->setError(d->fileEngine->error(), d->fileEngine->errorString());
- return success;
- }
- d->setError(PermissionsError, tr("No file engine available or engine does not support UnMapExtension"));
- return false;
+ unsetError();
+ return d->unmap(address);
}
/*!
bool QFile::resize(qint64 sz)
{
Q_D(QFile);
- fileEngine();
- if (isOpen() && d->fileEngine->pos() > sz)
+ if (isOpen() && QT_LSEEK(d->fd, 0, SEEK_CUR) > sz) {
seek(sz);
- if(d->fileEngine->setSize(sz)) {
- unsetError();
- return true;
}
- d->setError(QFile::ResizeError, d->fileEngine->errorString());
- return false;
+ int ret = 0;
+ if (d->fd != -1) {
+ Q_EINTR_LOOP(ret, QT_FTRUNCATE(d->fd, sz));
+ } else {
+ Q_EINTR_LOOP(ret, QT_TRUNCATE(d->fileEntry.nativeFilePath().constData(), sz));
+ }
+ d->metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
+ if (ret == -1) {
+ d->setError(QFile::ResizeError, qt_error_string(errno));
+ return false;
+ }
+ unsetError();
+ return true;
}
/*!
QFile::Permissions QFile::permissions() const
{
- return fileEngine()->permissions();
+ Q_D(const QFile);
+ bool exists = d->doStat(QFileSystemMetaData::Permissions | QFileSystemMetaData::LinkType);
+ if (!exists && !d->metaData.isLink())
+ return 0;
+ return d->metaData.permissions();
}
/*!
bool QFile::setPermissions(Permissions permissions)
{
Q_D(QFile);
- if(fileEngine()->setPermissions(permissions)) {
- unsetError();
- return true;
+ int error = 0;
+ if (!QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(permissions), &error)) {
+ d->setError(QFile::PermissionsError, qt_error_string(error));
+ return false;
}
- d->setError(QFile::PermissionsError, d->fileEngine->errorString());
- return false;
+ unsetError();
+ return true;
}
/*!
bool QFile::flush()
{
Q_D(QFile);
- if (Q_UNLIKELY(!d->fileEngine)) {
- qWarning("QFile::flush: No file engine. Is IODevice open?");
- return false;
- }
-
- if (!d->fileEngine->flush()) {
- QFile::FileError err = d->fileEngine->error();
- if(err == QFile::UnspecifiedError)
- err = QFile::WriteError;
- d->setError(err, d->fileEngine->errorString());
+ if (d->fd == -1) {
+ d->setError(QFile::WriteError, QString());
return false;
}
return true;
}
/*!
- Calls QFile::flush() and closes the file. Errors from flush are ignored.
+ Calls QFile::flush() and closes the file. Errors from flush are ignored.
- \sa QIODevice::close()
+ \sa QIODevice::close()
*/
void QFile::close()
{
const bool flushed = flush();
QIODevice::close();
- // keep earlier error from flush
- if (d->fileEngine->close() && flushed)
+ if (d->fd == -1) {
+ d->setError(QFile::UnspecifiedError, QString());
+ return;
+ }
+
+ d->metaData.clear();
+
+ // Close the file if we created the handle.
+ int ret = 0;
+ if (d->closeFileHandle) {
+ ret = qt_safe_close(d->fd);
+ }
+
+ // We must reset these guys regardless; calling close again after a
+ // failed close causes crashes on some systems.
+ d->fd = -1;
+ QList<uchar*> keys = d->maps.keys();
+ for (int i = 0; i < keys.count(); ++i) {
+ d->unmap(keys.at(i));
+ }
+
+ // Report errors.
+ if (ret != 0) {
+ d->setError(QFile::UnspecifiedError, qt_error_string(errno));
+ return;
+ }
+
+ if (flushed) {
unsetError();
- else if (flushed)
- d->setError(d->fileEngine->error(), d->fileEngine->errorString());
+ }
}
/*!
- Returns the size of the file.
+ Returns the size of the file.
- For regular empty files on Unix (e.g. those in \c /proc), this function
- returns 0; the contents of such a file are generated on demand in response
- to you calling read().
+ For regular empty files on Unix (e.g. those in \c /proc), this function
+ returns 0; the contents of such a file are generated on demand in response
+ to you calling read().
*/
-
qint64 QFile::size() const
{
- return fileEngine()->size();
+ Q_D(const QFile);
+ d->metaData.clear();
+ if (!d->doStat(QFileSystemMetaData::SizeAttribute))
+ return 0;
+ return d->metaData.size();
}
/*!
- Returns true if the end of the file has been reached; otherwise returns
- false.
+ Returns true if the end of the file has been reached; otherwise returns
+ false.
- For regular empty files on Unix (e.g. those in \c /proc), this function
- returns true, since the file system reports that the size of such a file is
- 0. Therefore, you should not depend on atEnd() when reading data from such a
- file, but rather call read() until no more data can be read.
+ For regular empty files on Unix (e.g. those in \c /proc), this function
+ returns true, since the file system reports that the size of such a file is
+ 0. Therefore, you should not depend on atEnd() when reading data from such a
+ file, but rather call read() until no more data can be read.
*/
bool QFile::atEnd() const
return false;
}
- if (off == d->pos && off == d->devicePos)
+ if (off == d->pos && off == d->devicePos) {
return true; // avoid expensive flush for NOP seek to current position
+ }
+
+ if (off < 0 || off != qint64(QT_OFF_T(off))) {
+ d->setError(QFile::PositionError, QString());
+ return false;
+ }
- if (!d->fileEngine->seek(off) || !QIODevice::seek(off)) {
- QFile::FileError err = d->fileEngine->error();
- if(err == QFile::UnspecifiedError)
- err = QFile::PositionError;
- d->setError(err, d->fileEngine->errorString());
+ if (Q_UNLIKELY(QT_LSEEK(d->fd, QT_OFF_T(off), SEEK_SET) == -1)) {
+ qWarning("QFile::seek: Cannot set file position %lld", off);
+ d->setError(QFile::PositionError, qt_error_string(errno));
+ return false;
+ }
+ if (!QIODevice::seek(off)) {
+ d->setError(QFile::PositionError, QString());
return false;
}
unsetError();
qint64 QFile::readLineData(char *data, qint64 maxlen)
{
Q_D(QFile);
- if (d->fileEngine->supportsExtension(QAbstractFileEngine::FastReadLineExtension)) {
- return d->fileEngine->readLine(data, maxlen);
+ if (d->fd != -1 && isSequential()) {
+ qint64 readSoFar = 0;
+ while (readSoFar < maxlen) {
+ char c;
+ qint64 readResult = readData(&c, 1);
+ if (readResult <= 0)
+ return (readSoFar > 0) ? readSoFar : -1;
+ ++readSoFar;
+ *data++ = c;
+ if (c == '\n')
+ return readSoFar;
+ }
+ return readSoFar;
}
// Fall back to QIODevice's readLine implementation if the engine
// cannot do it faster.
Q_D(QFile);
unsetError();
- qint64 read = d->fileEngine->read(data, len);
- if(read < 0) {
- QFile::FileError err = d->fileEngine->error();
- if(err == QFile::UnspecifiedError)
- err = QFile::ReadError;
- d->setError(err, d->fileEngine->errorString());
+ if (len < 0) {
+ d->setError(QFile::ReadError, qt_error_string(EINVAL));
+ return -1;
+ }
+
+ qint64 readBytes = 0;
+ bool eof = false;
+
+ if (d->fd != -1) {
+ ssize_t result;
+ do {
+ result = QT_READ(d->fd, data + readBytes, size_t(len - readBytes));
+ } while ((result == -1 && errno == EINTR)
+ || (result > 0 && (readBytes += result) < len));
+
+ eof = !(result == -1);
+ }
+
+ if (!eof && readBytes == 0) {
+ readBytes = -1;
+ d->setError(QFile::ReadError, qt_error_string(errno));
}
- return read;
+ return readBytes;
}
/*!
Q_D(QFile);
unsetError();
- qint64 ret = d->fileEngine->write(data, len);
- if(ret < 0) {
- QFile::FileError err = d->fileEngine->error();
- if(err == QFile::UnspecifiedError)
- err = QFile::WriteError;
- d->setError(err, d->fileEngine->errorString());
+ if (len < 0 || len != qint64(size_t(len))) {
+ d->setError(QFile::WriteError, qt_error_string(EINVAL));
+ return -1;
}
- return ret;
-}
-/*!
- \internal
- Returns the QIOEngine for this QFile object.
-*/
-QAbstractFileEngine *QFile::fileEngine() const
-{
- Q_D(const QFile);
- if(!d->fileEngine)
- d->fileEngine = QAbstractFileEngine::create(d->fileName);
- return d->fileEngine;
+ qint64 writtenBytes = 0;
+
+ if (d->fd != -1) {
+ ssize_t result;
+ do {
+ result = QT_WRITE(d->fd, data + writtenBytes, size_t(len - writtenBytes));
+ } while ((result == -1 && errno == EINTR)
+ || (result > 0 && (writtenBytes += result) < len));
+ }
+
+ if (len && writtenBytes == 0) {
+ writtenBytes = -1;
+ d->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno));
+ }
+
+ d->metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
+
+ return writtenBytes;
}
/*!
void QFile::unsetError()
{
Q_D(QFile);
- d->setError(QFile::NoError);
+ d->setError(QFile::NoError, QString());
}
#ifndef QT_NO_QOBJECT
QT_BEGIN_NAMESPACE
-
-class QAbstractFileEngine;
class QFilePrivate;
class Q_CORE_EXPORT QFile : public QIODevice
uchar *map(qint64 offset, qint64 size);
bool unmap(uchar *address);
- virtual QAbstractFileEngine *fileEngine() const;
-
-
protected:
#ifdef QT_NO_QOBJECT
QFile(QFilePrivate &dd);
// We mean it.
//
-#include "qabstractfileengine.h"
#include "qiodevice_p.h"
+#include "qfilesystementry_p.h"
+#include "qfilesystemmetadata_p.h"
QT_BEGIN_NAMESPACE
QFilePrivate();
~QFilePrivate();
- bool openExternalFile(int flags, int fd, QFile::FileHandleFlags handleFlags);
-
- QString fileName;
- mutable QAbstractFileEngine *fileEngine;
+ bool openExternalFile(QIODevice::OpenMode mode, int fd, QFile::FileHandleFlags handleFlags);
+ bool doStat(QFileSystemMetaData::MetaDataFlags flags) const;
+ bool unmap(uchar *ptr);
QFile::FileError error;
- void setError(QFile::FileError err);
+ QString errorString;
+ QFileSystemEntry fileEntry;
+ mutable QFileSystemMetaData metaData;
+ QHash<uchar *, QPair<int /*offset % PageSize*/, size_t /*length + offset % PageSize*/> > maps;
+ int fd;
+ bool closeFileHandle;
+
void setError(QFile::FileError err, const QString &errorString);
};
QT_BEGIN_NAMESPACE
-QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const
+QString QFileInfoPrivate::getFileName(const QFileInfoPrivate::FileName name) const
{
if (cache_enabled && !fileNames[(int)name].isNull())
return fileNames[(int)name];
QString ret;
switch (name) {
- case QAbstractFileEngine::CanonicalName:
- case QAbstractFileEngine::CanonicalPathName: {
+ case FileName::CanonicalName:
+ case FileName::CanonicalPathName: {
QFileSystemEntry entry = QFileSystemEngine::canonicalName(fileEntry, metaData);
if (cache_enabled) { // be smart and store both
- fileNames[QAbstractFileEngine::CanonicalName] = entry.filePath();
- fileNames[QAbstractFileEngine::CanonicalPathName] = entry.path();
+ fileNames[FileName::CanonicalName] = entry.filePath();
+ fileNames[FileName::CanonicalPathName] = entry.path();
}
- if (name == QAbstractFileEngine::CanonicalName)
+ if (name == FileName::CanonicalName)
ret = entry.filePath();
else
ret = entry.path();
break;
}
- case QAbstractFileEngine::LinkName:
+ case FileName::LinkName:
ret = QFileSystemEngine::getLinkTarget(fileEntry, metaData).filePath();
break;
- case QAbstractFileEngine::AbsoluteName:
- case QAbstractFileEngine::AbsolutePathName: {
+ case FileName::AbsoluteName:
+ case FileName::AbsolutePathName: {
QFileSystemEntry entry = QFileSystemEngine::absoluteName(fileEntry);
if (cache_enabled) { // be smart and store both
- fileNames[QAbstractFileEngine::AbsoluteName] = entry.filePath();
- fileNames[QAbstractFileEngine::AbsolutePathName] = entry.path();
+ fileNames[FileName::AbsoluteName] = entry.filePath();
+ fileNames[FileName::AbsolutePathName] = entry.path();
}
- if (name == QAbstractFileEngine::AbsoluteName)
+ if (name == FileName::AbsoluteName)
ret = entry.filePath();
else
ret = entry.path();
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return QLatin1String("");
- return d->getFileName(QAbstractFileEngine::AbsoluteName);
+ return d->getFileName(QFileInfoPrivate::AbsoluteName);
}
/*!
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return QLatin1String("");
- return d->getFileName(QAbstractFileEngine::CanonicalName);
+ return d->getFileName(QFileInfoPrivate::CanonicalName);
}
qWarning("QFileInfo::absolutePath: Constructed with empty filename");
return QLatin1String("");
}
- return d->getFileName(QAbstractFileEngine::AbsolutePathName);
+ return d->getFileName(QFileInfoPrivate::AbsolutePathName);
}
/*!
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return QLatin1String("");
- return d->getFileName(QAbstractFileEngine::CanonicalPathName);
+ return d->getFileName(QFileInfoPrivate::CanonicalPathName);
}
/*!
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return QLatin1String("");
- return d->getFileName(QAbstractFileEngine::LinkName);
+ return d->getFileName(QFileInfoPrivate::LinkName);
}
/*!
class QFileInfoPrivate : public QSharedData
{
public:
+ enum FileName {
+ DefaultName,
+ BaseName,
+ PathName,
+ AbsoluteName,
+ AbsolutePathName,
+ LinkName,
+ CanonicalName,
+ CanonicalPathName,
+ NFileNames
+ };
+
inline QFileInfoPrivate()
: QSharedData(),
isDefaultConstructed(true),
inline void clear() const {
metaData.clear();
- for (int i = 0; i < QAbstractFileEngine::NFileNames; i++)
+ for (int i = 0; i < FileName::NFileNames; i++)
fileNames[i].clear();
}
- QString getFileName(QAbstractFileEngine::FileName) const;
+ QString getFileName(const FileName name) const;
QFileSystemEntry fileEntry;
mutable QFileSystemMetaData metaData;
- mutable QString fileNames[QAbstractFileEngine::NFileNames];
+ mutable QString fileNames[FileName::NFileNames];
bool const isDefaultConstructed; // QFileInfo is a default constructed instance
bool cache_enabled;
#ifndef QT_NO_DEBUG
if (result.isEmpty())
- qWarning("QAbstractFileEngine::currentPath: " GETCWDFUNCNAME "() failed");
+ qWarning("QFileSystemEngine::currentPath: " GETCWDFUNCNAME "() failed");
#endif
#undef GETCWDFUNCNAME
//
#include "qplatformdefs.h"
-#include <QtCore/qdatetime.h>
-#include <QtCore/qabstractfileengine.h>
+#include "qdatetime.h"
#include "qfilesystementry_p.h"
+#include "qfile.h"
QT_BEGIN_NAMESPACE
#include "qplatformdefs.h"
#include "qdir.h"
#include "qfile_p.h"
-#include "qabstractfileengine_p.h"
#include "qfilesystemengine_p.h"
+#include "qdebug.h"
#include "qcore_unix_p.h"
#include "qcorecommon_p.h"
QT_BEGIN_NAMESPACE
-//************* QTemporaryFileEngine
-class QTemporaryFileEngine : public QAbstractFileEngine
-{
- Q_DECLARE_PRIVATE(QAbstractFileEngine)
-public:
- QTemporaryFileEngine(const QString &file, bool fileIsTemplate = true)
- : QAbstractFileEngine(), filePathIsTemplate(fileIsTemplate)
- {
- Q_D(QAbstractFileEngine);
- d->fileEntry = QFileSystemEntry(file);
-
- if (!filePathIsTemplate)
- QAbstractFileEngine::setFileName(file);
- }
-
- ~QTemporaryFileEngine();
-
- bool isReallyOpen();
- void setFileName(const QString &file);
- void setFileTemplate(const QString &fileTemplate);
-
- bool open(QIODevice::OpenMode flags);
- bool remove();
- bool rename(const QString &newName);
- bool close();
-
- bool filePathIsTemplate;
-};
-
-QTemporaryFileEngine::~QTemporaryFileEngine()
-{
- QAbstractFileEngine::close();
-}
-
-bool QTemporaryFileEngine::isReallyOpen()
-{
- Q_D(QAbstractFileEngine);
- return (d->fd != -1);
-
-}
-
-void QTemporaryFileEngine::setFileName(const QString &file)
-{
- // Really close the file, so we don't leak
- QAbstractFileEngine::close();
- QAbstractFileEngine::setFileName(file);
-}
-
-void QTemporaryFileEngine::setFileTemplate(const QString &fileTemplate)
-{
- Q_D(QAbstractFileEngine);
- if (filePathIsTemplate)
- d->fileEntry = QFileSystemEntry(fileTemplate);
-}
-
-bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
-{
- Q_D(QAbstractFileEngine);
- Q_ASSERT(!isReallyOpen());
-
- openMode |= QIODevice::ReadWrite;
-
- if (!filePathIsTemplate)
- return QAbstractFileEngine::open(openMode);
-
- QString qfilename = d->fileEntry.filePath();
-
- // "Nativify" :-)
- QFileSystemEntry::NativePath filename =
- QFileSystemEngine::absoluteName(QFileSystemEntry(qfilename)).nativeFilePath();
-
- // Find placeholder in native path
- uint phPos = filename.length();
- uint phLength = 0;
- while (phPos != 0) {
- --phPos;
-
- if (filename.at(phPos) == 'X') {
- ++phLength;
- continue;
- }
-
- // require atleast 6 for compatibility
- if (phLength >= 6 || filename.at(phPos) == '/') {
- ++phPos;
- break;
- }
-
- // start over
- phLength = 0;
- }
-
- // Ensure there is a placeholder mask
- if (phLength < 6) {
- filename.append(".XXXXXXXXXX");
- phPos = filename.length() - 10;
- phLength = 10;
- }
-
- Q_ASSERT(phLength >= 6);
- Q_ASSERT(phPos < filename.length());
- Q_ASSERT(phLength <= filename.length() - phPos);
-
- static const char tmpnamechars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
- char *data = filename.data();
- for (uint i = 0; i < phLength; i++) {
- data[i + phPos] = tmpnamechars[qrand() % 52];
- }
-
- // Create file and obtain handle
- d->fd = qt_safe_open(data, QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR, 0600);
-
- if (d->fd == -1) {
- setError(QFile::OpenError, qt_error_string(errno));
- return false;
- }
-
- d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromNativePath());
-
- d->closeFileHandle = true;
-
- filePathIsTemplate = false;
-
- d->openMode = openMode;
- d->metaData.clear();
-
- return true;
-}
-
-bool QTemporaryFileEngine::remove()
-{
- Q_D(QAbstractFileEngine);
- // Since the QTemporaryFileEngine::close() does not really close the file,
- // we must explicitly call QAbstractFileEngine::close() before we remove it.
- QAbstractFileEngine::close();
- if (QAbstractFileEngine::remove()) {
- d->fileEntry.clear();
- return true;
- }
- return false;
-}
-
-bool QTemporaryFileEngine::rename(const QString &newName)
-{
- QAbstractFileEngine::close();
- return QAbstractFileEngine::rename(newName);
-}
-
-bool QTemporaryFileEngine::close()
-{
- // Don't close the file, just seek to the front.
- seek(0);
- setError(QFile::UnspecifiedError, QString());
- return true;
-}
-
//************* QTemporaryFilePrivate
class QTemporaryFilePrivate : public QFilePrivate
{
{
Q_D(QTemporaryFile);
close();
- if (!d->fileName.isEmpty() && d->autoRemove)
+ if (!d->fileEntry.isEmpty() && d->autoRemove)
remove();
}
/*!
- \fn bool QTemporaryFile::open()
-
- A QTemporaryFile will always be opened in QIODevice::ReadWrite mode,
- this allows easy access to the data in the file. This function will
- return true upon success and will set the fileName() to the unique
- filename used.
+ A QTemporaryFile will always be opened in QIODevice::ReadWrite mode,
+ this allows easy access to the data in the file. This function will
+ return true upon success and will set the fileName() to the unique
+ filename used.
- \sa fileName()
+ \sa fileName()
*/
+bool QTemporaryFile::open()
+{
+ Q_D(QTemporaryFile);
+ if (Q_UNLIKELY(isOpen())) {
+ qWarning("QTemporaryFile::open: File (%s) already open", qPrintable(fileName()));
+ return false;
+ }
+
+ // "Nativify" :-)
+ QFileSystemEntry::NativePath filename =
+ QFileSystemEngine::absoluteName(QFileSystemEntry(d->templateName)).nativeFilePath();
+
+ // Find placeholder in native path
+ uint phPos = filename.length();
+ uint phLength = 0;
+ while (phPos != 0) {
+ --phPos;
+
+ if (filename.at(phPos) == 'X') {
+ ++phLength;
+ continue;
+ }
+
+ // require atleast 6 for compatibility
+ if (phLength >= 6 || filename.at(phPos) == '/') {
+ ++phPos;
+ break;
+ }
+
+ // start over
+ phLength = 0;
+ }
+
+ // Ensure there is a placeholder mask
+ if (phLength < 6) {
+ filename.append(".XXXXXXXXXX");
+ phPos = filename.length() - 10;
+ phLength = 10;
+ }
+
+ Q_ASSERT(phLength >= 6);
+ Q_ASSERT(phPos < filename.length());
+ Q_ASSERT(phLength <= filename.length() - phPos);
+
+ static const char tmpnamechars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ char *data = filename.data();
+ for (uint i = 0; i < phLength; i++) {
+ data[i + phPos] = tmpnamechars[qrand() % 52];
+ }
+
+ // Create file and obtain handle
+ d->fd = qt_safe_open(data, QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR, 0600);
+
+ if (d->fd == -1) {
+ d->setError(QFile::OpenError, qt_error_string(errno));
+ return false;
+ }
+
+ d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromNativePath());
+ d->closeFileHandle = true;
+ d->metaData.clear();
+
+ QIODevice::open(QIODevice::ReadWrite);
+
+ return true;
+}
/*!
- Returns true if the QTemporaryFile is in auto remove
- mode. Auto-remove mode will automatically delete the filename from
- disk upon destruction. This makes it very easy to create your
- QTemporaryFile object on the stack, fill it with data, read from
- it, and finally on function return it will automatically clean up
- after itself.
+ Returns true if the QTemporaryFile is in auto remove
+ mode. Auto-remove mode will automatically delete the filename from
+ disk upon destruction. This makes it very easy to create your
+ QTemporaryFile object on the stack, fill it with data, read from
+ it, and finally on function return it will automatically clean up
+ after itself.
- Auto-remove is on by default.
+ Auto-remove is on by default.
- \sa setAutoRemove(), remove()
+ \sa setAutoRemove(), remove()
*/
bool QTemporaryFile::autoRemove() const
{
}
/*!
- Returns the complete unique filename backing the QTemporaryFile
- object. This string is null before the QTemporaryFile is opened,
- afterwards it will contain the fileTemplate() plus
- additional characters to make it unique.
-
- \sa fileTemplate()
-*/
-
-QString QTemporaryFile::fileName() const
-{
- Q_D(const QTemporaryFile);
- if(d->fileName.isEmpty())
- return QString();
- return fileEngine()->fileName(QAbstractFileEngine::DefaultName);
-}
-
-/*!
Returns the set file template. The default file template will be
called qt_temp and be placed in QDir::tempPath().
}
/*!
- Sets the static portion of the file name to \a name. If the file
- template ends in XXXXXXXXXX that will automatically be replaced with
- the unique part of the filename, otherwise a filename will be
- determined automatically based on the static portion specified.
+ Sets the static portion of the file name to \a name. If the file
+ template ends in XXXXXXXXXX that will automatically be replaced with
+ the unique part of the filename, otherwise a filename will be
+ determined automatically based on the static portion specified.
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
{
Q_D(QTemporaryFile);
d->templateName = name;
- if (d->fileEngine)
- static_cast<QTemporaryFileEngine*>(d->fileEngine)->setFileTemplate(name);
-}
-
-/*!
- \internal
-*/
-
-QAbstractFileEngine *QTemporaryFile::fileEngine() const
-{
- Q_D(const QTemporaryFile);
- if(!d->fileEngine) {
- if (d->fileName.isEmpty())
- d->fileEngine = new QTemporaryFileEngine(d->templateName);
- else
- d->fileEngine = new QTemporaryFileEngine(d->fileName, false);
- }
- return d->fileEngine;
-}
-
-/*!
- \reimp
-
- Creates a unique file name for the temporary file, and opens it. You can
- get the unique name later by calling fileName(). The file is guaranteed to
- have been created by this function (i.e., it has never existed before).
-*/
-bool QTemporaryFile::open(OpenMode flags)
-{
- Q_D(QTemporaryFile);
- if (!d->fileName.isEmpty()) {
- if (static_cast<QTemporaryFileEngine*>(fileEngine())->isReallyOpen()) {
- setOpenMode(flags);
- return true;
- }
- }
-
- if (QFile::open(flags)) {
- d->fileName = d->fileEngine->fileName(QAbstractFileEngine::DefaultName);
- return true;
- }
- return false;
}
#ifndef QT_NO_QOBJECT
bool autoRemove() const;
void setAutoRemove(bool b);
- // ### Hides open(flags)
- bool open() { return open(QIODevice::ReadWrite); }
+ bool open();
- QString fileName() const;
QString fileTemplate() const;
void setFileTemplate(const QString &name);
- virtual QAbstractFileEngine *fileEngine() const;
-
-protected:
- bool open(OpenMode flags);
-
private:
friend class QFile;
Q_DISABLE_COPY(QTemporaryFile)
${CMAKE_SOURCE_DIR}/src/core/codecs/qtextcodec.cpp
${CMAKE_SOURCE_DIR}/src/core/global/qglobal.cpp
${CMAKE_SOURCE_DIR}/src/core/global/qt_error_string.cpp
- ${CMAKE_SOURCE_DIR}/src/core/io/qabstractfileengine.cpp
${CMAKE_SOURCE_DIR}/src/core/io/qbuffer.cpp
${CMAKE_SOURCE_DIR}/src/core/io/qdir.cpp
${CMAKE_SOURCE_DIR}/src/core/io/qdiriterator.cpp
}
if (filename.isEmpty())
- QTest::ignoreMessage(QtWarningMsg, "QAbstractFileEngine::open: No file name specified");
+ QTest::ignoreMessage(QtWarningMsg, "QFile::open: No file name specified");
if (ok) {
QVERIFY2(f.open(QIODevice::OpenMode(mode)),
void fileNameIsEmpty();
void autoRemove();
void write();
- void openCloseOpenClose();
void size();
void resize();
void openOnRootDrives();
void stressTest();
void rename();
void renameFdLeak();
- void reOpenThroughQFile();
void keepOpenMode();
void resetTemplateAfterError();
void setTemplateAfterOpen();
file.close();
}
-void tst_QTemporaryFile::openCloseOpenClose()
-{
- QString fileName;
- {
- // Create a temp file
- QTemporaryFile file("tempXXXXXX");
- file.setAutoRemove(true);
- QVERIFY(file.open());
- file.write("OLE");
- fileName = file.fileName();
- QVERIFY(QFile::exists(fileName));
- file.close();
-
- // Check that it still exists after being closed
- QVERIFY(QFile::exists(fileName));
- QVERIFY(!file.isOpen());
- QVERIFY(file.open());
- QCOMPARE(file.readAll(), QByteArray("OLE"));
- // Check that it's still the same file after being opened again.
- QCOMPARE(file.fileName(), fileName);
- }
- QVERIFY(!QFile::exists(fileName));
-}
-
void tst_QTemporaryFile::size()
{
QTemporaryFile file;
QVERIFY(qt_safe_close(fd) == -1 && errno == EBADF);
}
-void tst_QTemporaryFile::reOpenThroughQFile()
-{
- QByteArray data("abcdefghij");
-
- QTemporaryFile file;
- QVERIFY(((QFile &)file).open(QIODevice::WriteOnly));
- QCOMPARE(file.write(data), (qint64)data.size());
-
- file.close();
- QVERIFY(file.open());
- QCOMPARE(file.readAll(), data);
-}
-
void tst_QTemporaryFile::keepOpenMode()
{
QByteArray data("abcdefghij");
{
- QTemporaryFile file;
- QVERIFY(((QFile &)file).open(QIODevice::WriteOnly));
- QVERIFY(QIODevice::WriteOnly == file.openMode());
-
- QCOMPARE(file.write(data), (qint64)data.size());
- file.close();
-
- QVERIFY(((QFile &)file).open(QIODevice::ReadOnly));
- QVERIFY(QIODevice::ReadOnly == file.openMode());
- QCOMPARE(file.readAll(), data);
- }
-
- {
- QTemporaryFile file;
- QVERIFY(file.open());
- QCOMPARE(file.write(data), (qint64)data.size());
- QVERIFY(file.rename("temporary-file.txt"));
+ QTemporaryFile tmpfile;
+ QVERIFY(tmpfile.open());
+ QCOMPARE(tmpfile.write(data), (qint64)data.size());
+ QVERIFY(tmpfile.rename("temporary-file.txt"));
- QVERIFY(((QFile &)file).open(QIODevice::ReadOnly));
+ QFile file("temporary-file.txt");
+ QVERIFY(file.open(QIODevice::ReadOnly));
QVERIFY(QIODevice::ReadOnly == file.openMode());
QCOMPARE(file.readAll(), data);
-
- QVERIFY(((QFile &)file).open(QIODevice::WriteOnly));
- QVERIFY(QIODevice::WriteOnly == file.openMode());
}
}
QVERIFY( temp.open() );
QString const fileName = temp.fileName();
- QString const newTemplate("funny-path/funny-name-XXXXXX.tmp");
+ QString const newTemplate("funny-name-XXXXXX.tmp");
QVERIFY( !fileName.isEmpty() );
QVERIFY( QFile::exists(fileName) );
QCOMPARE( temp.fileTemplate(), newTemplate );
QVERIFY( temp.open() );
- QCOMPARE( temp.fileName(), fileName );
QCOMPARE( temp.fileTemplate(), newTemplate );
}