684 lines
19 KiB
C++
684 lines
19 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** 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$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "qplatformdefs.h"
|
|
#include "private/qabstractfileengine_p.h"
|
|
#include "private/qfsfileengine_p.h"
|
|
#include "private/qcore_unix_p.h"
|
|
#include "qfilesystementry_p.h"
|
|
#include "qfilesystemengine_p.h"
|
|
#include "qcoreapplication.h"
|
|
|
|
#ifndef QT_NO_FSFILEENGINE
|
|
|
|
#include "qfile.h"
|
|
#include "qdir.h"
|
|
#include "qdatetime.h"
|
|
#include "qvarlengtharray.h"
|
|
|
|
#include <sys/mman.h>
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include <errno.h>
|
|
#if defined(Q_OS_MACOS)
|
|
# include <private/qcore_mac_p.h>
|
|
#endif
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
/*!
|
|
\internal
|
|
|
|
Returns the stdio open flags corresponding to a QIODevice::OpenMode.
|
|
*/
|
|
static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
|
|
{
|
|
int oflags = QT_OPEN_RDONLY;
|
|
#ifdef QT_LARGEFILE_SUPPORT
|
|
oflags |= QT_OPEN_LARGEFILE;
|
|
#endif
|
|
|
|
if ((mode & QFile::ReadWrite) == QFile::ReadWrite)
|
|
oflags = QT_OPEN_RDWR;
|
|
else if (mode & QFile::WriteOnly)
|
|
oflags = QT_OPEN_WRONLY;
|
|
|
|
if (QFSFileEnginePrivate::openModeCanCreate(mode))
|
|
oflags |= QT_OPEN_CREAT;
|
|
|
|
if (mode & QFile::Truncate)
|
|
oflags |= QT_OPEN_TRUNC;
|
|
|
|
if (mode & QFile::Append)
|
|
oflags |= QT_OPEN_APPEND;
|
|
|
|
if (mode & QFile::NewOnly)
|
|
oflags |= QT_OPEN_EXCL;
|
|
|
|
return oflags;
|
|
}
|
|
|
|
static inline QString msgOpenDirectory()
|
|
{
|
|
const char message[] = QT_TRANSLATE_NOOP("QIODevice", "file to open is a directory");
|
|
#if QT_CONFIG(translation)
|
|
return QIODevice::tr(message);
|
|
#else
|
|
return QLatin1String(message);
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
|
|
{
|
|
Q_Q(QFSFileEngine);
|
|
|
|
Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
|
|
"QFSFileEngine no longer supports buffered mode; upper layer must buffer");
|
|
if (openMode & QIODevice::Unbuffered) {
|
|
int flags = openModeToOpenFlags(openMode);
|
|
|
|
// Try to open the file in unbuffered mode.
|
|
do {
|
|
fd = QT_OPEN(fileEntry.nativeFilePath().constData(), flags, 0666);
|
|
} while (fd == -1 && errno == EINTR);
|
|
|
|
// On failure, return and report the error.
|
|
if (fd == -1) {
|
|
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
|
|
qt_error_string(errno));
|
|
return false;
|
|
}
|
|
|
|
if (!(openMode & QIODevice::WriteOnly)) {
|
|
// we don't need this check if we tried to open for writing because then
|
|
// we had received EISDIR anyway.
|
|
if (QFileSystemEngine::fillMetaData(fd, metaData)
|
|
&& metaData.isDirectory()) {
|
|
q->setError(QFile::OpenError, msgOpenDirectory());
|
|
QT_CLOSE(fd);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Seek to the end when in Append mode.
|
|
if (flags & QFile::Append) {
|
|
int ret;
|
|
do {
|
|
ret = QT_LSEEK(fd, 0, SEEK_END);
|
|
} while (ret == -1 && errno == EINTR);
|
|
|
|
if (ret == -1) {
|
|
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
|
|
qt_error_string(int(errno)));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
fh = nullptr;
|
|
}
|
|
|
|
closeFileHandle = true;
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
bool QFSFileEnginePrivate::nativeClose()
|
|
{
|
|
return closeFdFh();
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
|
|
*/
|
|
bool QFSFileEnginePrivate::nativeFlush()
|
|
{
|
|
return fh ? flushFh() : fd != -1;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
\since 5.1
|
|
*/
|
|
bool QFSFileEnginePrivate::nativeSyncToDisk()
|
|
{
|
|
Q_Q(QFSFileEngine);
|
|
int ret;
|
|
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
|
|
EINTR_LOOP(ret, fdatasync(nativeHandle()));
|
|
#else
|
|
EINTR_LOOP(ret, fsync(nativeHandle()));
|
|
#endif
|
|
if (ret != 0)
|
|
q->setError(QFile::WriteError, qt_error_string(errno));
|
|
return ret == 0;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len)
|
|
{
|
|
Q_Q(QFSFileEngine);
|
|
|
|
if (fh && nativeIsSequential()) {
|
|
size_t readBytes = 0;
|
|
int oldFlags = fcntl(QT_FILENO(fh), F_GETFL);
|
|
for (int i = 0; i < 2; ++i) {
|
|
// Unix: Make the underlying file descriptor non-blocking
|
|
if ((oldFlags & O_NONBLOCK) == 0)
|
|
fcntl(QT_FILENO(fh), F_SETFL, oldFlags | O_NONBLOCK);
|
|
|
|
// Cross platform stdlib read
|
|
size_t read = 0;
|
|
do {
|
|
read = fread(data + readBytes, 1, size_t(len - readBytes), fh);
|
|
} while (read == 0 && !feof(fh) && errno == EINTR);
|
|
if (read > 0) {
|
|
readBytes += read;
|
|
break;
|
|
} else {
|
|
if (readBytes)
|
|
break;
|
|
readBytes = read;
|
|
}
|
|
|
|
// Unix: Restore the blocking state of the underlying socket
|
|
if ((oldFlags & O_NONBLOCK) == 0) {
|
|
fcntl(QT_FILENO(fh), F_SETFL, oldFlags);
|
|
if (readBytes == 0) {
|
|
int readByte = 0;
|
|
do {
|
|
readByte = fgetc(fh);
|
|
} while (readByte == -1 && errno == EINTR);
|
|
if (readByte != -1) {
|
|
*data = uchar(readByte);
|
|
readBytes += 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Unix: Restore the blocking state of the underlying socket
|
|
if ((oldFlags & O_NONBLOCK) == 0) {
|
|
fcntl(QT_FILENO(fh), F_SETFL, oldFlags);
|
|
}
|
|
if (readBytes == 0 && !feof(fh)) {
|
|
// if we didn't read anything and we're not at EOF, it must be an error
|
|
q->setError(QFile::ReadError, qt_error_string(int(errno)));
|
|
return -1;
|
|
}
|
|
return readBytes;
|
|
}
|
|
|
|
return readFdFh(data, len);
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
qint64 QFSFileEnginePrivate::nativeReadLine(char *data, qint64 maxlen)
|
|
{
|
|
return readLineFdFh(data, maxlen);
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len)
|
|
{
|
|
return writeFdFh(data, len);
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
qint64 QFSFileEnginePrivate::nativePos() const
|
|
{
|
|
return posFdFh();
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
bool QFSFileEnginePrivate::nativeSeek(qint64 pos)
|
|
{
|
|
return seekFdFh(pos);
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
int QFSFileEnginePrivate::nativeHandle() const
|
|
{
|
|
return fh ? fileno(fh) : fd;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
bool QFSFileEnginePrivate::nativeIsSequential() const
|
|
{
|
|
return isSequentialFdFh();
|
|
}
|
|
|
|
bool QFSFileEngine::link(const QString &newName)
|
|
{
|
|
Q_D(QFSFileEngine);
|
|
QSystemError error;
|
|
bool ret = QFileSystemEngine::createLink(d->fileEntry, QFileSystemEntry(newName), error);
|
|
if (!ret) {
|
|
setError(QFile::RenameError, error.toString());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
qint64 QFSFileEnginePrivate::nativeSize() const
|
|
{
|
|
return sizeFdFh();
|
|
}
|
|
|
|
bool QFSFileEngine::caseSensitive() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
QString QFSFileEngine::currentPath(const QString &)
|
|
{
|
|
return QFileSystemEngine::currentPath().filePath();
|
|
}
|
|
|
|
|
|
QFileInfoList QFSFileEngine::drives()
|
|
{
|
|
QFileInfoList ret;
|
|
ret.append(QFileInfo(rootPath()));
|
|
return ret;
|
|
}
|
|
|
|
bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const
|
|
{
|
|
if (!tried_stat || !metaData.hasFlags(flags)) {
|
|
tried_stat = 1;
|
|
|
|
int localFd = fd;
|
|
if (fh && fileEntry.isEmpty())
|
|
localFd = QT_FILENO(fh);
|
|
if (localFd != -1)
|
|
QFileSystemEngine::fillMetaData(localFd, metaData);
|
|
|
|
if (metaData.missingFlags(flags) && !fileEntry.isEmpty())
|
|
QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags));
|
|
}
|
|
|
|
return metaData.exists();
|
|
}
|
|
|
|
bool QFSFileEnginePrivate::isSymlink() const
|
|
{
|
|
if (!metaData.hasFlags(QFileSystemMetaData::LinkType))
|
|
QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::LinkType);
|
|
|
|
return metaData.isLink();
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
|
|
{
|
|
Q_D(const QFSFileEngine);
|
|
|
|
if (type & Refresh)
|
|
d->metaData.clear();
|
|
|
|
QAbstractFileEngine::FileFlags ret = { };
|
|
|
|
if (type & FlagsMask)
|
|
ret |= LocalDiskFlag;
|
|
|
|
bool exists;
|
|
{
|
|
QFileSystemMetaData::MetaDataFlags queryFlags = { };
|
|
|
|
queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type.toInt()))
|
|
& QFileSystemMetaData::Permissions;
|
|
|
|
if (type & TypesMask)
|
|
queryFlags |= QFileSystemMetaData::AliasType
|
|
| QFileSystemMetaData::LinkType
|
|
| QFileSystemMetaData::FileType
|
|
| QFileSystemMetaData::DirectoryType
|
|
| QFileSystemMetaData::BundleType
|
|
| QFileSystemMetaData::WasDeletedAttribute;
|
|
|
|
if (type & FlagsMask)
|
|
queryFlags |= QFileSystemMetaData::HiddenAttribute
|
|
| QFileSystemMetaData::ExistsAttribute;
|
|
else if (type & ExistsFlag)
|
|
queryFlags |= QFileSystemMetaData::WasDeletedAttribute;
|
|
|
|
queryFlags |= QFileSystemMetaData::LinkType;
|
|
|
|
exists = d->doStat(queryFlags);
|
|
}
|
|
|
|
if (!exists && !d->metaData.isLink())
|
|
return ret;
|
|
|
|
if (exists && (type & PermsMask))
|
|
ret |= FileFlags(uint(d->metaData.permissions().toInt()));
|
|
|
|
if (type & TypesMask) {
|
|
if (d->metaData.isAlias()) {
|
|
ret |= LinkType;
|
|
} else {
|
|
if ((type & LinkType) && d->metaData.isLink())
|
|
ret |= LinkType;
|
|
if (exists) {
|
|
if (d->metaData.isFile()) {
|
|
ret |= FileType;
|
|
} else if (d->metaData.isDirectory()) {
|
|
ret |= DirectoryType;
|
|
if ((type & BundleType) && d->metaData.isBundle())
|
|
ret |= BundleType;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type & FlagsMask) {
|
|
// the inode existing does not mean the file exists
|
|
if (!d->metaData.wasDeleted())
|
|
ret |= ExistsFlag;
|
|
if (d->fileEntry.isRoot())
|
|
ret |= RootFlag;
|
|
else if (d->metaData.isHidden())
|
|
ret |= HiddenFlag;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
QByteArray QFSFileEngine::id() const
|
|
{
|
|
Q_D(const QFSFileEngine);
|
|
if (d->fd != -1)
|
|
return QFileSystemEngine::id(d->fd);
|
|
return QFileSystemEngine::id(d->fileEntry);
|
|
}
|
|
|
|
QString QFSFileEngine::fileName(FileName file) const
|
|
{
|
|
Q_D(const QFSFileEngine);
|
|
switch (file) {
|
|
case BundleName:
|
|
return QFileSystemEngine::bundleName(d->fileEntry);
|
|
case BaseName:
|
|
return d->fileEntry.fileName();
|
|
case PathName:
|
|
return d->fileEntry.path();
|
|
case AbsoluteName:
|
|
case AbsolutePathName: {
|
|
QFileSystemEntry entry(QFileSystemEngine::absoluteName(d->fileEntry));
|
|
return file == AbsolutePathName ? entry.path() : entry.filePath();
|
|
}
|
|
case CanonicalName:
|
|
case CanonicalPathName: {
|
|
QFileSystemEntry entry(QFileSystemEngine::canonicalName(d->fileEntry, d->metaData));
|
|
return file == CanonicalPathName ? entry.path() : entry.filePath();
|
|
}
|
|
case LinkName:
|
|
if (d->isSymlink()) {
|
|
QFileSystemEntry entry = QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData);
|
|
return entry.filePath();
|
|
}
|
|
return QString();
|
|
case JunctionName:
|
|
return QString();
|
|
case DefaultName:
|
|
case NFileNames:
|
|
break;
|
|
}
|
|
return d->fileEntry.filePath();
|
|
}
|
|
|
|
bool QFSFileEngine::isRelativePath() const
|
|
{
|
|
Q_D(const QFSFileEngine);
|
|
return d->fileEntry.filePath().length() ? d->fileEntry.filePath().at(0) != QLatin1Char('/') : true;
|
|
}
|
|
|
|
uint QFSFileEngine::ownerId(FileOwner own) const
|
|
{
|
|
Q_D(const QFSFileEngine);
|
|
static const uint nobodyID = (uint) -2;
|
|
|
|
if (d->doStat(QFileSystemMetaData::OwnerIds))
|
|
return d->metaData.ownerId(own);
|
|
|
|
return nobodyID;
|
|
}
|
|
|
|
QString QFSFileEngine::owner(FileOwner own) const
|
|
{
|
|
if (own == OwnerUser)
|
|
return QFileSystemEngine::resolveUserName(ownerId(own));
|
|
return QFileSystemEngine::resolveGroupName(ownerId(own));
|
|
}
|
|
|
|
bool QFSFileEngine::setPermissions(uint perms)
|
|
{
|
|
Q_D(QFSFileEngine);
|
|
QSystemError error;
|
|
bool ok;
|
|
if (d->fd != -1)
|
|
ok = QFileSystemEngine::setPermissions(d->fd, QFile::Permissions(perms), error);
|
|
else
|
|
ok = QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error);
|
|
if (!ok) {
|
|
setError(QFile::PermissionsError, error.toString());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool QFSFileEngine::setSize(qint64 size)
|
|
{
|
|
Q_D(QFSFileEngine);
|
|
bool ret = false;
|
|
if (d->fd != -1)
|
|
ret = QT_FTRUNCATE(d->fd, size) == 0;
|
|
else if (d->fh)
|
|
ret = QT_FTRUNCATE(QT_FILENO(d->fh), size) == 0;
|
|
else
|
|
ret = QT_TRUNCATE(d->fileEntry.nativeFilePath().constData(), size) == 0;
|
|
if (!ret)
|
|
setError(QFile::ResizeError, qt_error_string(errno));
|
|
return ret;
|
|
}
|
|
|
|
bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
|
|
{
|
|
Q_D(QFSFileEngine);
|
|
|
|
if (d->openMode == QIODevice::NotOpen) {
|
|
setError(QFile::PermissionsError, qt_error_string(EACCES));
|
|
return false;
|
|
}
|
|
|
|
QSystemError error;
|
|
if (!QFileSystemEngine::setFileTime(d->nativeHandle(), newDate, time, error)) {
|
|
setError(QFile::PermissionsError, error.toString());
|
|
return false;
|
|
}
|
|
|
|
d->metaData.clearFlags(QFileSystemMetaData::Times);
|
|
return true;
|
|
}
|
|
|
|
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
|
|
{
|
|
qint64 maxFileOffset = std::numeric_limits<QT_OFF_T>::max();
|
|
#if (defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)) && Q_PROCESSOR_WORDSIZE == 4
|
|
// The Linux mmap2 system call on 32-bit takes a page-shifted 32-bit
|
|
// integer so the maximum offset is 1 << (32+12) (the shift is always 12,
|
|
// regardless of the actual page size). Unfortunately, the mmap64()
|
|
// function is known to be broken in all Linux libcs (glibc, uclibc, musl
|
|
// and Bionic): all of them do the right shift, but don't confirm that the
|
|
// result fits into the 32-bit parameter to the kernel.
|
|
|
|
maxFileOffset = qMin((Q_INT64_C(1) << (32+12)) - 1, maxFileOffset);
|
|
#endif
|
|
|
|
Q_Q(QFSFileEngine);
|
|
if (openMode == QIODevice::NotOpen) {
|
|
q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
|
|
return nullptr;
|
|
}
|
|
|
|
if (offset < 0 || offset > maxFileOffset
|
|
|| size < 0 || quint64(size) > quint64(size_t(-1))) {
|
|
q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
|
|
return nullptr;
|
|
}
|
|
|
|
// 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("QFSFileEngine::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;
|
|
|
|
int sharemode = MAP_SHARED;
|
|
if (flags & QFileDevice::MapPrivateOption) {
|
|
sharemode = MAP_PRIVATE;
|
|
access |= PROT_WRITE;
|
|
}
|
|
|
|
#if defined(Q_OS_INTEGRITY)
|
|
int pageSize = sysconf(_SC_PAGESIZE);
|
|
#else
|
|
int pageSize = getpagesize();
|
|
#endif
|
|
int extra = offset % pageSize;
|
|
|
|
if (quint64(size + extra) > quint64((size_t)-1)) {
|
|
q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
|
|
return nullptr;
|
|
}
|
|
|
|
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((void*)nullptr, realSize,
|
|
access, sharemode, nativeHandle(), realOffset);
|
|
if (MAP_FAILED != mapAddress) {
|
|
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(int(EACCES)));
|
|
break;
|
|
case ENFILE:
|
|
case ENOMEM:
|
|
q->setError(QFile::ResourceError, qt_error_string(int(errno)));
|
|
break;
|
|
case EINVAL:
|
|
// size are out of bounds
|
|
default:
|
|
q->setError(QFile::UnspecifiedError, qt_error_string(int(errno)));
|
|
break;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool QFSFileEnginePrivate::unmap(uchar *ptr)
|
|
{
|
|
#if !defined(Q_OS_INTEGRITY)
|
|
Q_Q(QFSFileEngine);
|
|
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 (-1 == munmap(start, len)) {
|
|
q->setError(QFile::UnspecifiedError, qt_error_string(errno));
|
|
return false;
|
|
}
|
|
maps.remove(ptr);
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
bool QFSFileEngine::cloneTo(QAbstractFileEngine *target)
|
|
{
|
|
Q_D(QFSFileEngine);
|
|
if ((target->fileFlags(LocalDiskFlag) & LocalDiskFlag) == 0)
|
|
return false;
|
|
|
|
int srcfd = d->nativeHandle();
|
|
int dstfd = target->handle();
|
|
return QFileSystemEngine::cloneFile(srcfd, dstfd, d->metaData);
|
|
}
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
#endif // QT_NO_FSFILEENGINE
|