summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfsfileengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qfsfileengine.cpp')
-rw-r--r--src/corelib/io/qfsfileengine.cpp873
1 files changed, 873 insertions, 0 deletions
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
new file mode 100644
index 0000000..61ea7cc
--- /dev/null
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -0,0 +1,873 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfsfileengine_p.h"
+#include "qfsfileengine_iterator_p.h"
+#include "qdatetime.h"
+#include "qdiriterator.h"
+#include "qset.h"
+
+#ifndef QT_NO_FSFILEENGINE
+
+#if !defined(Q_OS_WINCE)
+#include <errno.h>
+#endif
+#include <stdio.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN
+# ifndef S_ISREG
+# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
+# endif
+# ifndef S_ISCHR
+# define S_ISCHR(x) (((x) & S_IFMT) == S_IFCHR)
+# endif
+# ifndef S_ISFIFO
+# define S_ISFIFO(x) false
+# endif
+# ifndef S_ISSOCK
+# define S_ISSOCK(x) false
+# endif
+# ifndef INVALID_FILE_ATTRIBUTES
+# define INVALID_FILE_ATTRIBUTES (DWORD (-1))
+# endif
+#endif
+
+
+/*! \class QFSFileEngine
+ \brief The QFSFileEngine class implements Qt's default file engine.
+ \since 4.1
+
+ This class is part of the file engine framework in Qt. If you only want to
+ access files or directories, use QFile, QFileInfo or QDir instead.
+
+ QFSFileEngine is the default file engine for accessing regular files. It
+ is provided for convenience; by subclassing this class, you can alter its
+ behavior slightly, without having to write a complete QAbstractFileEngine
+ subclass. To install your custom file engine, you must also subclass
+ QAbstractFileEngineHandler and create an instance of your handler.
+
+ It can also be useful to create a QFSFileEngine object directly if you
+ need to use the local file system inside QAbstractFileEngine::create(), in
+ order to avoid recursion (as higher-level classes tend to call
+ QAbstractFileEngine::create()).
+*/
+
+//**************** QFSFileEnginePrivate
+QFSFileEnginePrivate::QFSFileEnginePrivate() : QAbstractFileEnginePrivate()
+{
+ init();
+}
+
+/*!
+ \internal
+*/
+void QFSFileEnginePrivate::init()
+{
+ is_sequential = 0;
+ tried_stat = 0;
+#ifdef Q_OS_UNIX
+ need_lstat = 1;
+ is_link = 0;
+#endif
+ openMode = QIODevice::NotOpen;
+ fd = -1;
+ fh = 0;
+ lastIOCommand = IOFlushCommand;
+ lastFlushFailed = false;
+ closeFileHandle = false;
+#ifdef Q_OS_WIN
+ fileAttrib = INVALID_FILE_ATTRIBUTES;
+ fileHandle = INVALID_HANDLE_VALUE;
+ cachedFd = -1;
+#endif
+#ifdef Q_USE_DEPRECATED_MAP_API
+ fileMapHandle = INVALID_HANDLE_VALUE;
+#endif
+}
+
+/*!
+ \internal
+
+ Returns the canonicalized form of \a path (i.e., with all symlinks
+ resolved, and all redundant path elements removed.
+*/
+QString QFSFileEnginePrivate::canonicalized(const QString &path)
+{
+ if (path.isEmpty())
+ return path;
+
+ QFileInfo fi;
+ const QChar slash(QLatin1Char('/'));
+ QString tmpPath = path;
+ int separatorPos = 0;
+ QSet<QString> nonSymlinks;
+ QSet<QString> known;
+
+ known.insert(path);
+ do {
+#ifdef Q_OS_WIN
+ // UNC, skip past the first two elements
+ if (separatorPos == 0 && tmpPath.startsWith(QLatin1String("//")))
+ separatorPos = tmpPath.indexOf(slash, 2);
+ if (separatorPos != -1)
+#endif
+ separatorPos = tmpPath.indexOf(slash, separatorPos + 1);
+ QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos);
+ if (!nonSymlinks.contains(prefix)) {
+ fi.setFile(prefix);
+ if (fi.isSymLink()) {
+ QString target = fi.symLinkTarget();
+ if (separatorPos != -1) {
+ if (fi.isDir() && !target.endsWith(slash))
+ target.append(slash);
+ target.append(tmpPath.mid(separatorPos));
+ }
+ tmpPath = QDir::cleanPath(target);
+ separatorPos = 0;
+
+ if (known.contains(tmpPath))
+ return QString();
+ known.insert(tmpPath);
+ } else {
+ nonSymlinks.insert(prefix);
+ }
+ }
+ } while (separatorPos != -1);
+
+ return QDir::cleanPath(tmpPath);
+}
+
+/*!
+ Constructs a QFSFileEngine for the file name \a file.
+*/
+QFSFileEngine::QFSFileEngine(const QString &file) : QAbstractFileEngine(*new QFSFileEnginePrivate)
+{
+ Q_D(QFSFileEngine);
+ d->filePath = QDir::fromNativeSeparators(file);
+ d->nativeInitFileName();
+}
+
+/*!
+ Constructs a QFSFileEngine.
+*/
+QFSFileEngine::QFSFileEngine() : QAbstractFileEngine(*new QFSFileEnginePrivate)
+{
+}
+
+/*!
+ \internal
+*/
+QFSFileEngine::QFSFileEngine(QFSFileEnginePrivate &dd)
+ : QAbstractFileEngine(dd)
+{
+}
+
+/*!
+ Destructs the QFSFileEngine.
+*/
+QFSFileEngine::~QFSFileEngine()
+{
+ Q_D(QFSFileEngine);
+ if (d->closeFileHandle) {
+ if (d->fh) {
+ int ret;
+ do {
+ ret = fclose(d->fh);
+ } while (ret == EOF && errno == EINTR);
+ } else if (d->fd != -1) {
+ int ret;
+ do {
+ ret = QT_CLOSE(d->fd);
+ } while (ret == -1 && errno == EINTR);
+ }
+ }
+ QList<uchar*> keys = d->maps.keys();
+ for (int i = 0; i < keys.count(); ++i)
+ unmap(keys.at(i));
+}
+
+/*!
+ \reimp
+*/
+void QFSFileEngine::setFileName(const QString &file)
+{
+ Q_D(QFSFileEngine);
+ d->init();
+ d->filePath = QDir::fromNativeSeparators(file);
+ d->nativeInitFileName();
+}
+
+/*!
+ \reimp
+*/
+bool QFSFileEngine::open(QIODevice::OpenMode openMode)
+{
+ Q_D(QFSFileEngine);
+ if (d->filePath.isEmpty()) {
+ qWarning("QFSFileEngine::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->lastFlushFailed = false;
+ d->tried_stat = 0;
+ d->fh = 0;
+ d->fd = -1;
+
+ return d->nativeOpen(openMode);
+}
+
+/*!
+ Opens the file handle \a fh in \a openMode mode. Returns true on
+ success; otherwise returns false.
+*/
+bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh)
+{
+ Q_D(QFSFileEngine);
+
+ // 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->lastFlushFailed = false;
+ d->closeFileHandle = false;
+ d->nativeFilePath.clear();
+ d->filePath.clear();
+ d->tried_stat = 0;
+ d->fd = -1;
+
+ return d->openFh(openMode, fh);
+}
+
+/*!
+ Opens the file handle \a fh using the open mode \a flags.
+*/
+bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
+{
+ Q_Q(QFSFileEngine);
+ this->fh = fh;
+ fd = -1;
+
+ // Seek to the end when in Append mode.
+ if (openMode & QIODevice::Append) {
+ int ret;
+ do {
+ ret = QT_FSEEK(fh, 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;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ Opens the file descriptor \a fd in \a openMode mode. Returns true
+ on success; otherwise returns false.
+*/
+bool QFSFileEngine::open(QIODevice::OpenMode openMode, int fd)
+{
+ Q_D(QFSFileEngine);
+
+ // 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->lastFlushFailed = false;
+ d->closeFileHandle = false;
+ d->nativeFilePath.clear();
+ d->filePath.clear();
+ d->fh = 0;
+ d->fd = -1;
+ d->tried_stat = 0;
+
+ return d->openFd(openMode, fd);
+}
+
+
+/*!
+ Opens the file descriptor \a fd to the file engine, using the open mode \a
+ flags.
+*/
+bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
+{
+ Q_Q(QFSFileEngine);
+ this->fd = fd;
+ fh = 0;
+
+ // Seek to the end when in Append mode.
+ if (openMode & 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;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ \reimp
+*/
+bool QFSFileEngine::close()
+{
+ Q_D(QFSFileEngine);
+ d->openMode = QIODevice::NotOpen;
+ return d->nativeClose();
+}
+
+/*!
+ \internal
+*/
+bool QFSFileEnginePrivate::closeFdFh()
+{
+ Q_Q(QFSFileEngine);
+ if (fd == -1 && !fh)
+ return false;
+
+ // Flush the file if it's buffered, and if the last flush didn't fail.
+ bool flushed = !fh || (!lastFlushFailed && q->flush());
+ bool closed = true;
+ tried_stat = 0;
+
+ // Close the file if we created the handle.
+ if (closeFileHandle) {
+ int ret;
+ do {
+ if (fh) {
+ // Close buffered file.
+ ret = fclose(fh) != 0 ? -1 : 0;
+ } else {
+ // Close unbuffered file.
+ ret = QT_CLOSE(fd);
+ }
+ } while (ret == -1 && errno == EINTR);
+
+ // We must reset these guys regardless; calling close again after a
+ // failed close causes crashes on some systems.
+ fh = 0;
+ fd = -1;
+ closed = (ret == 0);
+ }
+
+ // Report errors.
+ if (!flushed || !closed) {
+ if (flushed) {
+ // If not flushed, we want the flush error to fall through.
+ q->setError(QFile::UnspecifiedError, qt_error_string(errno));
+ }
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ \reimp
+*/
+bool QFSFileEngine::flush()
+{
+ Q_D(QFSFileEngine);
+ if ((d->openMode & QIODevice::WriteOnly) == 0) {
+ // Nothing in the write buffers, so flush succeeds in doing
+ // nothing.
+ return true;
+ }
+ return d->nativeFlush();
+}
+
+/*!
+ \internal
+*/
+bool QFSFileEnginePrivate::flushFh()
+{
+ Q_Q(QFSFileEngine);
+
+ // Never try to flush again if the last flush failed. Otherwise you can
+ // get crashes on some systems (AIX).
+ if (lastFlushFailed)
+ return false;
+
+ int ret = fflush(fh);
+
+ lastFlushFailed = (ret != 0);
+ lastIOCommand = QFSFileEnginePrivate::IOFlushCommand;
+
+ if (ret != 0) {
+ q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
+ qt_error_string(errno));
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \reimp
+*/
+qint64 QFSFileEngine::size() const
+{
+ Q_D(const QFSFileEngine);
+ return d->nativeSize();
+}
+
+/*!
+ \internal
+*/
+qint64 QFSFileEnginePrivate::sizeFdFh() const
+{
+ Q_Q(const QFSFileEngine);
+ // ### Fix this function, it should not stat unless the file is closed.
+ QT_STATBUF st;
+ int ret = 0;
+ const_cast<QFSFileEngine *>(q)->flush();
+ if (fh && nativeFilePath.isEmpty()) {
+ // Buffered stdlib mode.
+ // ### This should really be an ftell
+ ret = QT_FSTAT(QT_FILENO(fh), &st);
+ } else if (fd == -1) {
+ // Stateless stat.
+ ret = QT_STAT(nativeFilePath.constData(), &st);
+ } else {
+ // Unbuffered stdio mode.
+ ret = QT_FSTAT(fd, &st);
+ }
+ if (ret == -1)
+ return 0;
+ return st.st_size;
+}
+
+/*!
+ \reimp
+*/
+qint64 QFSFileEngine::pos() const
+{
+ Q_D(const QFSFileEngine);
+ return d->nativePos();
+}
+
+/*!
+ \internal
+*/
+qint64 QFSFileEnginePrivate::posFdFh() const
+{
+ if (fh)
+ return qint64(QT_FTELL(fh));
+ return QT_LSEEK(fd, 0, SEEK_CUR);
+}
+
+/*!
+ \reimp
+*/
+bool QFSFileEngine::seek(qint64 pos)
+{
+ Q_D(QFSFileEngine);
+ return d->nativeSeek(pos);
+}
+
+/*!
+ \internal
+*/
+bool QFSFileEnginePrivate::seekFdFh(qint64 pos)
+{
+ Q_Q(QFSFileEngine);
+
+ // On Windows' stdlib implementation, the results of calling fread and
+ // fwrite are undefined if not called either in sequence, or if preceded
+ // with a call to fflush().
+ if (lastIOCommand != QFSFileEnginePrivate::IOFlushCommand && !q->flush())
+ return false;
+
+ if (fh) {
+ // Buffered stdlib mode.
+ int ret;
+ do {
+ ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ q->setError(QFile::ReadError, qt_error_string(int(errno)));
+ return false;
+ }
+ } else {
+ // Unbuffered stdio mode.
+ if (QT_LSEEK(fd, pos, SEEK_SET) == -1) {
+ qWarning("QFile::at: Cannot set file position %lld", pos);
+ q->setError(QFile::PositionError, qt_error_string(errno));
+ return false;
+ }
+ }
+ return true;
+}
+
+/*!
+ \reimp
+*/
+int QFSFileEngine::handle() const
+{
+ Q_D(const QFSFileEngine);
+ return d->nativeHandle();
+}
+
+/*!
+ \reimp
+*/
+qint64 QFSFileEngine::read(char *data, qint64 maxlen)
+{
+ Q_D(QFSFileEngine);
+
+ // On Windows' stdlib implementation, the results of calling fread and
+ // fwrite are undefined if not called either in sequence, or if preceded
+ // with a call to fflush().
+ if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
+ flush();
+ d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
+ }
+
+ return d->nativeRead(data, maxlen);
+}
+
+/*!
+ \internal
+*/
+qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
+{
+ Q_Q(QFSFileEngine);
+
+ // Buffered stdlib mode.
+ if (fh) {
+ qint64 readBytes = 0;
+ qint64 read = 0;
+ int retry = 0;
+
+ // Read in blocks of 4k to avoid platform limitations (Windows
+ // commonly bails out if you read or write too large blocks at once).
+ qint64 bytesToRead;
+ do {
+ if (retry == 1)
+ retry = 2;
+
+ bytesToRead = qMin<qint64>(4096, len - read);
+ do {
+ readBytes = fread(data + read, 1, size_t(bytesToRead), fh);
+ } while (readBytes == 0 && !feof(fh) && errno == EINTR);
+
+ if (readBytes > 0) {
+ read += readBytes;
+ } else if (!retry && feof(fh)) {
+ // Synchronize and try again (just once though).
+ if (++retry == 1)
+ QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET);
+ }
+ } while (retry == 1 || (readBytes == bytesToRead && read < len));
+
+ // Return the number of bytes read, or if nothing was read, return -1
+ // if an error occurred, or 0 if we detected EOF.
+ if (read == 0) {
+ q->setError(QFile::ReadError, qt_error_string(int(errno)));
+ if (!feof(fh))
+ read = -1;
+ }
+ return read;
+ }
+
+ // Unbuffered stdio mode.
+ qint64 ret = 0;
+ if (len) {
+ int result;
+ qint64 read = 0;
+ errno = 0;
+
+ // Read in blocks of 4k to avoid platform limitations (Windows
+ // commonly bails out if you read or write too large blocks at once).
+ do {
+ qint64 bytesToRead = qMin<qint64>(4096, len - read);
+ do {
+ result = QT_READ(fd, data + read, int(bytesToRead));
+ } while (result == -1 && errno == EINTR);
+ if (result > 0)
+ read += result;
+ } while (result > 0 && read < len);
+
+ // Return the number of bytes read, or if nothing was read, return -1
+ // if an error occurred.
+ if (read > 0) {
+ ret += read;
+ } else if (read == 0 && result < 0) {
+ ret = -1;
+ q->setError(QFile::ReadError, qt_error_string(errno));
+ }
+ }
+ return ret;
+}
+
+/*!
+ \reimp
+*/
+qint64 QFSFileEngine::readLine(char *data, qint64 maxlen)
+{
+ Q_D(QFSFileEngine);
+
+ // On Windows' stdlib implementation, the results of calling fread and
+ // fwrite are undefined if not called either in sequence, or if preceded
+ // with a call to fflush().
+ if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
+ flush();
+ d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
+ }
+
+ return d->nativeReadLine(data, maxlen);
+}
+
+/*!
+ \internal
+*/
+qint64 QFSFileEnginePrivate::readLineFdFh(char *data, qint64 maxlen)
+{
+ Q_Q(QFSFileEngine);
+ if (!fh)
+ return q->QAbstractFileEngine::readLine(data, maxlen);
+
+ QT_OFF_T oldPos = 0;
+#ifdef Q_OS_WIN
+ bool seq = q->isSequential();
+ if (!seq)
+#endif
+ oldPos = QT_FTELL(fh);
+
+ // QIODevice::readLine() passes maxlen - 1 to QFile::readLineData()
+ // because it has made space for the '\0' at the end of data. But fgets
+ // does the same, so we'd get two '\0' at the end - passing maxlen + 1
+ // solves this.
+ if (!fgets(data, int(maxlen + 1), fh)) {
+ if (!feof(fh))
+ q->setError(QFile::ReadError, qt_error_string(int(errno)));
+ return -1; // error
+ }
+
+#ifdef Q_OS_WIN
+ if (seq)
+ return qstrlen(data);
+#endif
+
+ qint64 lineLength = QT_FTELL(fh) - oldPos;
+ return lineLength > 0 ? lineLength : qstrlen(data);
+}
+
+/*!
+ \reimp
+*/
+qint64 QFSFileEngine::write(const char *data, qint64 len)
+{
+ Q_D(QFSFileEngine);
+
+ // On Windows' stdlib implementation, the results of calling fread and
+ // fwrite are undefined if not called either in sequence, or if preceded
+ // with a call to fflush().
+ if (d->lastIOCommand != QFSFileEnginePrivate::IOWriteCommand) {
+ flush();
+ d->lastIOCommand = QFSFileEnginePrivate::IOWriteCommand;
+ }
+
+ return d->nativeWrite(data, len);
+}
+
+/*!
+ \internal
+*/
+qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
+{
+ Q_Q(QFSFileEngine);
+ qint64 result;
+ qint64 written = 0;
+
+ do {
+ // Write blocks of 4k to avoid platform limitations (Windows commonly
+ // bails out if you read or write too large blocks at once).
+ qint64 bytesToWrite = qMin<qint64>(4096, len - written);
+ if (fh) {
+ do {
+ // Buffered stdlib mode.
+ result = qint64(fwrite(data + written, 1, size_t(bytesToWrite), fh));
+ } while (result == 0 && errno == EINTR);
+ if (bytesToWrite > 0 && result == 0)
+ result = -1;
+ } else {
+ do {
+ // Unbuffered stdio mode.
+ result = QT_WRITE(fd, data + written, bytesToWrite);
+ } while (result == -1 && errno == EINTR);
+ }
+ if (result > 0)
+ written += qint64(result);
+ } while (written < len && result > 0);
+
+ // If we read anything, return that with success. Otherwise, set an error,
+ // and return the last return value.
+ if (result > 0)
+ return written;
+ q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno));
+ return result;
+}
+
+/*!
+ \internal
+*/
+QAbstractFileEngine::Iterator *QFSFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+{
+ return new QFSFileEngineIterator(filters, filterNames);
+}
+
+/*!
+ \internal
+*/
+QAbstractFileEngine::Iterator *QFSFileEngine::endEntryList()
+{
+ return 0;
+}
+
+/*!
+ \internal
+*/
+QStringList QFSFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
+{
+ return QAbstractFileEngine::entryList(filters, filterNames);
+}
+
+/*!
+ \reimp
+*/
+bool QFSFileEngine::isSequential() const
+{
+ Q_D(const QFSFileEngine);
+ if (d->is_sequential == 0)
+ d->is_sequential = d->nativeIsSequential() ? 1 : 2;
+ return d->is_sequential == 1;
+}
+
+/*!
+ \internal
+*/
+bool QFSFileEnginePrivate::isSequentialFdFh() const
+{
+ if (!tried_stat)
+ doStat();
+ if (could_stat) {
+#ifdef Q_OS_UNIX
+ return (st.st_mode & S_IFMT) != S_IFREG;
+ // ### WINDOWS!
+#endif
+ }
+ return true;
+}
+
+/*!
+ \reimp
+*/
+bool QFSFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
+{
+ Q_D(QFSFileEngine);
+ if (extension == AtEndExtension && d->fh && isSequential())
+ return feof(d->fh);
+
+ if (extension == MapExtension) {
+ const MapExtensionOption *options = (MapExtensionOption*)(option);
+ MapExtensionReturn *returnValue = static_cast<MapExtensionReturn*>(output);
+ returnValue->address = d->map(options->offset, options->size, options->flags);
+ return (returnValue->address != 0);
+ }
+ if (extension == UnMapExtension) {
+ UnMapExtensionOption *options = (UnMapExtensionOption*)option;
+ return d->unmap(options->address);
+ }
+
+ return false;
+}
+
+/*!
+ \reimp
+*/
+bool QFSFileEngine::supportsExtension(Extension extension) const
+{
+ Q_D(const QFSFileEngine);
+ if (extension == AtEndExtension && d->fh && isSequential())
+ return true;
+ if (extension == FastReadLineExtension && d->fh)
+ return true;
+ if (extension == FastReadLineExtension && d->fd != -1 && isSequential())
+ return true;
+ if (extension == UnMapExtension || extension == MapExtension)
+ return true;
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_FSFILEENGINE