src/corelib/io/qfile.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/corelib/io/qfile.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1657 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qdebug.h"
+#include "qfile.h"
+#include "qfsfileengine.h"
+#include "qtemporaryfile.h"
+#include "qlist.h"
+#include "qfileinfo.h"
+#include "private/qiodevice_p.h"
+#include "private/qfile_p.h"
+#if defined(QT_BUILD_CORE_LIB)
+# include "qcoreapplication.h"
+#endif
+
+#ifdef QT_NO_QOBJECT
+#define tr(X) QString::fromLatin1(X)
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static const int QFILE_WRITEBUFFER_SIZE = 16384;
+
+static QByteArray locale_encode(const QString &f)
+{
+#ifndef Q_OS_DARWIN
+    return f.toLocal8Bit();
+#else
+    // Mac always expects UTF-8... and decomposed...
+    return f.normalized(QString::NormalizationForm_D).toUtf8();
+#endif
+}
+
+static QString locale_decode(const QByteArray &f)
+{
+#ifndef Q_OS_DARWIN
+    return QString::fromLocal8Bit(f);
+#else
+    // Mac always gives us UTF-8 and decomposed, we want that composed...
+    return QString::fromUtf8(f).normalized(QString::NormalizationForm_C);
+#endif
+}
+
+//************* QFilePrivate
+QFile::EncoderFn QFilePrivate::encoder = locale_encode;
+QFile::DecoderFn QFilePrivate::decoder = locale_decode;
+
+QFilePrivate::QFilePrivate()
+    : fileEngine(0), lastWasWrite(false),
+      writeBuffer(QFILE_WRITEBUFFER_SIZE), error(QFile::NoError)
+{
+}
+
+QFilePrivate::~QFilePrivate()
+{
+    delete fileEngine;
+    fileEngine = 0;
+}
+
+bool
+QFilePrivate::openExternalFile(int flags, int fd)
+{
+#ifdef QT_NO_FSFILEENGINE
+    Q_UNUSED(flags);
+    Q_UNUSED(fd);
+    return false;
+#else
+    delete fileEngine;
+    fileEngine = 0;
+    QFSFileEngine *fe = new QFSFileEngine;
+    fe->setFileName(fileName);
+    fileEngine = fe;
+    return fe->open(QIODevice::OpenMode(flags), fd);
+#endif
+}
+
+bool
+QFilePrivate::openExternalFile(int flags, FILE *fh)
+{
+#ifdef QT_NO_FSFILEENGINE
+    Q_UNUSED(flags);
+    Q_UNUSED(fh);
+    return false;
+#else
+    delete fileEngine;
+    fileEngine = 0;
+    QFSFileEngine *fe = new QFSFileEngine;
+    fe->setFileName(fileName);
+    fileEngine = fe;
+    return fe->open(QIODevice::OpenMode(flags), fh);
+#endif
+}
+
+inline bool QFilePrivate::ensureFlushed() const
+{
+    // This function ensures that the write buffer has been flushed (const
+    // because certain const functions need to call it.
+    if (lastWasWrite) {
+        const_cast<QFilePrivate *>(this)->lastWasWrite = false;
+        if (!const_cast<QFile *>(q_func())->flush())
+            return false;
+    }
+    return true;
+}
+
+void
+QFilePrivate::setError(QFile::FileError err)
+{
+    error = err;
+    errorString.clear();
+}
+
+void
+QFilePrivate::setError(QFile::FileError err, const QString &errStr)
+{
+    error = err;
+    errorString = errStr;
+}
+
+void
+QFilePrivate::setError(QFile::FileError err, int errNum)
+{
+    error = err;
+    errorString = qt_error_string(errNum);
+}
+
+//************* QFile
+
+/*!
+    \class QFile
+    \brief The QFile class provides an interface for reading from and writing to files.
+
+    \ingroup io
+
+    \reentrant
+
+    QFile is an I/O device for reading and writing text and binary
+    files and \l{The Qt Resource System}{resources}. A QFile may be
+    used by itself or, more conveniently, with a QTextStream or
+    QDataStream.
+
+    The file name is usually passed in the constructor, but it can be
+    set at any time using setFileName(). QFile expects the file
+    separator to be '/' regardless of operating system. The use of
+    other separators (e.g., '\\') is not supported.
+
+    You can check for a file's existence using exists(), and remove a
+    file using remove(). (More advanced file system related operations
+    are provided by QFileInfo and QDir.)
+
+    The file is opened with open(), closed with close(), and flushed
+    with flush(). Data is usually read and written using QDataStream
+    or QTextStream, but you can also call the QIODevice-inherited
+    functions read(), readLine(), readAll(), write(). QFile also
+    inherits getChar(), putChar(), and ungetChar(), which work one
+    character at a time.
+
+    The size of the file is returned by size(). You can get the
+    current file position using pos(), or move to a new file position
+    using seek(). If you've reached the end of the file, atEnd()
+    returns true.
+
+    \section1 Reading Files Directly
+
+    The following example reads a text file line by line:
+
+    \snippet doc/src/snippets/file/file.cpp 0
+
+    The QIODevice::Text flag passed to open() tells Qt to convert
+    Windows-style line terminators ("\\r\\n") into C++-style
+    terminators ("\\n"). By default, QFile assumes binary, i.e. it
+    doesn't perform any conversion on the bytes stored in the file.
+
+    \section1 Using Streams to Read Files
+
+    The next example uses QTextStream to read a text file
+    line by line:
+
+    \snippet doc/src/snippets/file/file.cpp 1
+
+    QTextStream takes care of converting the 8-bit data stored on
+    disk into a 16-bit Unicode QString. By default, it assumes that
+    the user system's local 8-bit encoding is used (e.g., ISO 8859-1
+    for most of Europe; see QTextCodec::codecForLocale() for
+    details). This can be changed using setCodec().
+
+    To write text, we can use operator<<(), which is overloaded to
+    take a QTextStream on the left and various data types (including
+    QString) on the right:
+
+    \snippet doc/src/snippets/file/file.cpp 2
+
+    QDataStream is similar, in that you can use operator<<() to write
+    data and operator>>() to read it back. See the class
+    documentation for details.
+
+    When you use QFile, QFileInfo, and QDir to access the file system
+    with Qt, you can use Unicode file names. On Unix, these file
+    names are converted to an 8-bit encoding. If you want to use
+    standard C++ APIs (\c <cstdio> or \c <iostream>) or
+    platform-specific APIs to access files instead of QFile, you can
+    use the encodeName() and decodeName() functions to convert
+    between Unicode file names and 8-bit file names.
+
+    On Unix, there are some special system files (e.g. in \c /proc) for which
+    size() will always return 0, yet you may still be able to read more data
+    from such a file; the data is generated in direct response to you calling
+    read(). In this case, however, you cannot use atEnd() to determine if
+    there is more data to read (since atEnd() will return true for a file that
+    claims to have size 0). Instead, you should either call readAll(), or call
+    read() or readLine() repeatedly until no more data can be read. The next
+    example uses QTextStream to read \c /proc/modules line by line:
+
+    \snippet doc/src/snippets/file/file.cpp 3
+
+    \section1 Signals
+
+    Unlike other QIODevice implementations, such as QTcpSocket, QFile does not
+    emit the aboutToClose(), bytesWritten(), or readyRead() signals. This
+    implementation detail means that QFile is not suitable for reading and
+    writing certain types of files, such as device files on Unix platforms.
+
+    \section1 Platform Specific Issues
+
+    File permissions are handled differently on Linux/Mac OS X and
+    Windows.  In a non \l{QIODevice::isWritable()}{writable}
+    directory on Linux, files cannot be created. This is not always
+    the case on Windows, where, for instance, the 'My Documents'
+    directory usually is not writable, but it is still possible to
+    create files in it.
+
+    \sa QTextStream, QDataStream, QFileInfo, QDir, {The Qt Resource System}
+*/
+
+/*!
+    \enum QFile::FileError
+
+    This enum describes the errors that may be returned by the error()
+    function.
+
+    \value NoError          No error occurred.
+    \value ReadError        An error occurred when reading from the file.
+    \value WriteError       An error occurred when writing to the file.
+    \value FatalError       A fatal error occurred.
+    \value ResourceError
+    \value OpenError        The file could not be opened.
+    \value AbortError       The operation was aborted.
+    \value TimeOutError     A timeout occurred.
+    \value UnspecifiedError An unspecified error occurred.
+    \value RemoveError      The file could not be removed.
+    \value RenameError      The file could not be renamed.
+    \value PositionError    The position in the file could not be changed.
+    \value ResizeError      The file could not be resized.
+    \value PermissionsError The file could not be accessed.
+    \value CopyError        The file could not be copied.
+
+    \omitvalue ConnectError
+*/
+
+/*!
+    \enum QFile::Permission
+
+    This enum is used by the permission() function to report the
+    permissions and ownership of a file. The values may be OR-ed
+    together to test multiple permissions and ownership values.
+
+    \value ReadOwner The file is readable by the owner of the file.
+    \value WriteOwner The file is writable by the owner of the file.
+    \value ExeOwner The file is executable by the owner of the file.
+    \value ReadUser The file is readable by the user.
+    \value WriteUser The file is writable by the user.
+    \value ExeUser The file is executable by the user.
+    \value ReadGroup The file is readable by the group.
+    \value WriteGroup The file is writable by the group.
+    \value ExeGroup The file is executable by the group.
+    \value ReadOther The file is readable by anyone.
+    \value WriteOther The file is writable by anyone.
+    \value ExeOther The file is executable by anyone.
+
+    \warning Because of differences in the platforms supported by Qt,
+    the semantics of ReadUser, WriteUser and ExeUser are
+    platform-dependent: On Unix, the rights of the owner of the file
+    are returned and on Windows the rights of the current user are
+    returned. This behavior might change in a future Qt version.
+
+    Note that Qt does not by default check for permissions on NTFS
+    file systems, as this may decrease the performance of file
+    handling considerably. It is possible to force permission checking
+    on NTFS by including the following code in your source:
+
+    \snippet doc/src/snippets/ntfsp.cpp 0
+
+    Permission checking is then turned on and off by incrementing and
+    decrementing \c qt_ntfs_permission_lookup by 1.
+
+    \snippet doc/src/snippets/ntfsp.cpp 1
+*/
+
+#ifdef QT3_SUPPORT
+/*!
+    \typedef QFile::PermissionSpec
+
+    Use QFile::Permission instead.
+*/
+#endif
+
+#ifdef QT_NO_QOBJECT
+QFile::QFile()
+    : QIODevice(*new QFilePrivate)
+{
+}
+QFile::QFile(const QString &name)
+    : QIODevice(*new QFilePrivate)
+{
+    d_func()->fileName = name;
+}
+QFile::QFile(QFilePrivate &dd)
+    : QIODevice(dd)
+{
+}
+#else
+/*!
+    \internal
+*/
+QFile::QFile()
+    : QIODevice(*new QFilePrivate, 0)
+{
+}
+/*!
+    Constructs a new file object with the given \a parent.
+*/
+QFile::QFile(QObject *parent)
+    : QIODevice(*new QFilePrivate, parent)
+{
+}
+/*!
+    Constructs a new file object to represent the file with the given \a name.
+*/
+QFile::QFile(const QString &name)
+    : QIODevice(*new QFilePrivate, 0)
+{
+    Q_D(QFile);
+    d->fileName = name;
+}
+/*!
+    Constructs a new file object with the given \a parent to represent the
+    file with the specified \a name.
+*/
+QFile::QFile(const QString &name, QObject *parent)
+    : QIODevice(*new QFilePrivate, parent)
+{
+    Q_D(QFile);
+    d->fileName = name;
+}
+/*!
+    \internal
+*/
+QFile::QFile(QFilePrivate &dd, QObject *parent)
+    : QIODevice(dd, parent)
+{
+}
+#endif
+
+/*!
+    Destroys the file object, closing it if necessary.
+*/
+QFile::~QFile()
+{
+    close();
+}
+
+/*!
+    Returns the name set by setFileName() or to the QFile
+    constructors.
+
+    \sa setFileName(), QFileInfo::fileName()
+*/
+QString QFile::fileName() const
+{
+    return fileEngine()->fileName(QAbstractFileEngine::DefaultName);
+}
+
+/*!
+    Sets the \a name of the file. The name can have no path, a
+    relative path, or an absolute path.
+
+    Do not call this function if the file has already been opened.
+
+    If the file name has no path or a relative path, the path used
+    will be the application's current directory path
+    \e{at the time of the open()} call.
+
+    Example:
+    \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 0
+
+    Note that the directory separator "/" works for all operating
+    systems supported by Qt.
+
+    \sa fileName(), QFileInfo, QDir
+*/
+void
+QFile::setFileName(const QString &name)
+{
+    Q_D(QFile);
+    if (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;
+}
+
+/*!
+    \fn QString QFile::decodeName(const char *localFileName)
+
+    \overload
+
+    Returns the Unicode version of the given \a localFileName. See
+    encodeName() for details.
+*/
+
+/*!
+    By default, this function converts \a fileName to the local 8-bit
+    encoding determined by the user's locale. This is sufficient for
+    file names that the user chooses. File names hard-coded into the
+    application should only use 7-bit ASCII filename characters.
+
+    \sa decodeName() setEncodingFunction()
+*/
+
+QByteArray
+QFile::encodeName(const QString &fileName)
+{
+    return (*QFilePrivate::encoder)(fileName);
+}
+
+/*!
+    \typedef QFile::EncoderFn
+
+    This is a typedef for a pointer to a function with the following
+    signature:
+
+    \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 1
+
+    \sa setEncodingFunction(), encodeName()
+*/
+
+/*!
+    This does the reverse of QFile::encodeName() using \a localFileName.
+
+    \sa setDecodingFunction(), encodeName()
+*/
+
+QString
+QFile::decodeName(const QByteArray &localFileName)
+{
+    return (*QFilePrivate::decoder)(localFileName);
+}
+
+/*!
+    \fn void QFile::setEncodingFunction(EncoderFn function)
+
+    \nonreentrant
+
+    Sets the \a function for encoding Unicode file names. The
+    default encodes in the locale-specific 8-bit encoding.
+
+    \sa encodeName(), setDecodingFunction()
+*/
+
+void
+QFile::setEncodingFunction(EncoderFn f)
+{
+    if (!f)
+        f = locale_encode;
+    QFilePrivate::encoder = f;
+}
+
+/*!
+    \typedef QFile::DecoderFn
+
+    This is a typedef for a pointer to a function with the following
+    signature:
+
+    \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 2
+
+    \sa setDecodingFunction()
+*/
+
+/*!
+    \fn void QFile::setDecodingFunction(DecoderFn function)
+
+    \nonreentrant
+
+    Sets the \a function for decoding 8-bit file names. The
+    default uses the locale-specific 8-bit encoding.
+
+    \sa setEncodingFunction(), decodeName()
+*/
+
+void
+QFile::setDecodingFunction(DecoderFn f)
+{
+    if (!f)
+        f = locale_decode;
+    QFilePrivate::decoder = f;
+}
+
+/*!
+    \overload
+
+    Returns true if the file specified by fileName() exists; otherwise
+    returns false.
+
+    \sa fileName(), setFileName()
+*/
+
+bool
+QFile::exists() const
+{
+    // 0x1000000 = QAbstractFileEngine::Refresh, forcing an update
+    return (fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask
+                                    | QAbstractFileEngine::FileFlag(0x1000000)) & QAbstractFileEngine::ExistsFlag);
+}
+
+/*!
+    Returns true if the file specified by \a fileName exists; otherwise
+    returns false.
+*/
+
+bool
+QFile::exists(const QString &fileName)
+{
+    return QFileInfo(fileName).exists();
+}
+
+/*!
+    \fn QString QFile::symLinkTarget() const
+    \since 4.2
+    \overload
+
+    Returns the absolute path of the file or directory a symlink (or shortcut
+    on Windows) points to, or a an empty string if the object isn't a symbolic
+    link.
+
+    This name may not represent an existing file; it is only a string.
+    QFile::exists() returns true if the symlink points to an existing file.
+
+    \sa fileName() setFileName()
+*/
+
+/*!
+    \obsolete
+
+    Use symLinkTarget() instead.
+*/
+QString
+QFile::readLink() const
+{
+    return fileEngine()->fileName(QAbstractFileEngine::LinkName);
+}
+
+/*!
+    \fn static QString QFile::symLinkTarget(const QString &fileName)
+    \since 4.2
+
+    Returns the absolute path of the file or directory referred to by the
+    symlink (or shortcut on Windows) specified by \a fileName, or returns an
+    empty string if the \a fileName does not correspond to a symbolic link.
+
+    This name may not represent an existing file; it is only a string.
+    QFile::exists() returns true if the symlink points to an existing file.
+*/
+
+/*!
+    \obsolete
+
+    Use symLinkTarget() instead.
+*/
+QString
+QFile::readLink(const QString &fileName)
+{
+    return QFileInfo(fileName).readLink();
+}
+
+/*!
+    Removes the file specified by fileName(). Returns true if successful;
+    otherwise returns false.
+
+    The file is closed before it is removed.
+
+    \sa setFileName()
+*/
+
+bool
+QFile::remove()
+{
+    Q_D(QFile);
+    if (d->fileName.isEmpty()) {
+        qWarning("QFile::remove: Empty or null file name");
+        return false;
+    }
+    close();
+    if(error() == QFile::NoError) {
+        if(fileEngine()->remove()) {
+            unsetError();
+            return true;
+        }
+        d->setError(QFile::RemoveError, fileEngine()->errorString());
+    }
+    return false;
+}
+
+/*!
+    \overload
+
+    Removes the file specified by the \a fileName given.
+
+    Returns true if successful; otherwise returns false.
+
+    \sa remove()
+*/
+
+bool
+QFile::remove(const QString &fileName)
+{
+    return QFile(fileName).remove();
+}
+
+/*!
+    Renames the file currently specified by fileName() to \a newName.
+    Returns true if successful; otherwise returns false.
+
+    If a file with the name \a newName already exists, rename() returns false
+    (i.e., QFile will not overwrite it).
+
+    The file is closed before it is renamed.
+
+    \sa setFileName()
+*/
+
+bool
+QFile::rename(const QString &newName)
+{
+    Q_D(QFile);
+    if (d->fileName.isEmpty()) {
+        qWarning("QFile::rename: Empty or null file name");
+        return false;
+    }
+    if (QFile(newName).exists()) {
+        // ### Race condition. If a file is moved in after this, it /will/ be
+        // overwritten. On Unix, the proper solution is to use hardlinks:
+        // return ::link(old, new) && ::remove(old);
+        d->setError(QFile::RenameError, tr("Destination file exists"));
+        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
+            fileEngine()->setFileName(newName);
+            d->fileName = newName;
+            return true;
+        }
+
+        if (isSequential()) {
+            d->setError(QFile::RenameError, tr("Will not rename sequential file using block copy"));
+            return false;
+        }
+
+        QFile out(newName);
+        if (open(QIODevice::ReadOnly)) {
+            if (out.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+                bool error = false;
+                char block[4096];
+                qint64 bytes;
+                while ((bytes = read(block, sizeof(block))) > 0) {
+                    if (bytes != out.write(block, bytes)) {
+                        d->setError(QFile::RenameError, out.errorString());
+                        error = true;
+                        break;
+                    }
+                }
+                if (bytes == -1) {
+                    d->setError(QFile::RenameError, errorString());
+                    error = true;
+                }
+                if(!error) {
+                    if (!remove()) {
+                        d->setError(QFile::RenameError, tr("Cannot remove source file"));
+                        error = true;
+                    }
+                }
+                if (error) {
+                    out.remove();
+                } else {
+                    fileEngine()->setFileName(newName);
+                    setPermissions(permissions());
+                    unsetError();
+                    setFileName(newName);
+                }
+                close();
+                return !error;
+            }
+            close();
+        }
+        d->setError(QFile::RenameError, out.isOpen() ? errorString() : out.errorString());
+    }
+    return false;
+}
+
+/*!
+    \overload
+
+    Renames the file \a oldName to \a newName. Returns true if
+    successful; otherwise returns false.
+
+    If a file with the name \a newName already exists, rename() returns false
+    (i.e., QFile will not overwrite it).
+
+    \sa rename()
+*/
+
+bool
+QFile::rename(const QString &oldName, const QString &newName)
+{
+    return QFile(oldName).rename(newName);
+}
+
+/*!
+
+    Creates a link named \a linkName that points to the file currently specified by
+    fileName().  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.
+
+    This function will not overwrite an already existing entity in the file system;
+    in this case, \c link() will return false and set \l{QFile::}{error()} to
+    return \l{QFile::}{RenameError}.
+
+    \note To create a valid link on Windows, \a linkName must have a \c{.lnk} file extension.
+
+    \note On Symbian, no link is created and false is returned if fileName()
+    currently specifies a directory.
+
+    \sa setFileName()
+*/
+
+bool
+QFile::link(const QString &linkName)
+{
+    Q_D(QFile);
+    if (d->fileName.isEmpty()) {
+        qWarning("QFile::link: Empty or null file name");
+        return false;
+    }
+    QFileInfo fi(linkName);
+    if(fileEngine()->link(fi.absoluteFilePath())) {
+        unsetError();
+        return true;
+    }
+    d->setError(QFile::RenameError, fileEngine()->errorString());
+    return false;
+}
+
+/*!
+    \overload
+
+    Creates a link named \a linkName that points to the file \a fileName. 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.
+
+    \sa link()
+*/
+
+bool
+QFile::link(const QString &fileName, const QString &linkName)
+{
+    return QFile(fileName).link(linkName);
+}
+
+/*!
+    Copies the file currently specified by fileName() to a file called
+    \a newName.  Returns true if successful; otherwise returns false.
+
+    Note that if a file with the name \a newName already exists,
+    copy() returns false (i.e. QFile will not overwrite it).
+
+    The source file is closed before it is copied.
+
+    \sa setFileName()
+*/
+
+bool
+QFile::copy(const QString &newName)
+{
+    Q_D(QFile);
+    if (d->fileName.isEmpty()) {
+        qWarning("QFile::copy: Empty or null file name");
+        return false;
+    }
+    if (QFile(newName).exists()) {
+        // ### Race condition. If a file is moved in after this, it /will/ be
+        // overwritten. On Unix, the proper solution is to use hardlinks:
+        // return ::link(old, new) && ::remove(old); See also rename().
+        d->setError(QFile::CopyError, tr("Destination file exists"));
+        return false;
+    }
+    unsetError();
+    close();
+    if(error() == QFile::NoError) {
+        if(fileEngine()->copy(newName)) {
+            unsetError();
+            return true;
+        } else {
+            bool error = false;
+            if(!open(QFile::ReadOnly)) {
+                error = true;
+                d->setError(QFile::CopyError, tr("Cannot open %1 for input").arg(d->fileName));
+            } else {
+                QString fileTemplate = QLatin1String("%1/qt_temp.XXXXXX");
+#ifdef QT_NO_TEMPORARYFILE
+                QFile out(fileTemplate.arg(QFileInfo(newName).path()));
+                if (!out.open(QIODevice::ReadWrite))
+                    error = true;
+#else
+                QTemporaryFile out(fileTemplate.arg(QFileInfo(newName).path()));
+                if (!out.open()) {
+                    out.setFileTemplate(fileTemplate.arg(QDir::tempPath()));
+                    if (!out.open())
+                        error = true;
+                }
+#endif
+                if (error) {
+                    out.close();
+                    d->setError(QFile::CopyError, tr("Cannot open for output"));
+                } else {
+                    char block[4096];
+                    qint64 totalRead = 0;
+                    while(!atEnd()) {
+                        qint64 in = read(block, sizeof(block));
+                        if (in <= 0)
+                            break;
+                        totalRead += in;
+                        if(in != out.write(block, in)) {
+                            d->setError(QFile::CopyError, tr("Failure to write block"));
+                            error = true;
+                            break;
+                        }
+                    }
+
+                    if (totalRead != size()) {
+                        // Unable to read from the source. The error string is
+                        // already set from read().
+                        error = true;
+                    }
+                    if (!error && !out.rename(newName)) {
+                        error = true;
+                        d->setError(QFile::CopyError, tr("Cannot create %1 for output").arg(newName));
+                    }
+#ifdef QT_NO_TEMPORARYFILE
+                    if (error)
+                        out.remove();
+#else
+                    if (!error)
+                        out.setAutoRemove(false);
+#endif
+                }
+                close();
+            }
+            if(!error) {
+                QFile::setPermissions(newName, permissions());
+                unsetError();
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+/*!
+    \overload
+
+    Copies the file \a fileName to \a newName. Returns true if successful;
+    otherwise returns false.
+
+    If a file with the name \a newName already exists, copy() returns false
+    (i.e., QFile will not overwrite it).
+
+    \sa rename()
+*/
+
+bool
+QFile::copy(const QString &fileName, const QString &newName)
+{
+    return QFile(fileName).copy(newName);
+}
+
+/*!
+    Returns true if the file can only be manipulated sequentially;
+    otherwise returns false.
+
+    Most files support random-access, but some special files may not.
+
+    \sa QIODevice::isSequential()
+*/
+bool QFile::isSequential() const
+{
+    Q_D(const QFile);
+    return d->fileEngine && d->fileEngine->isSequential();
+}
+
+/*!
+    Opens the file using OpenMode \a mode, returning true if successful;
+    otherwise false.
+
+    The \a mode must be QIODevice::ReadOnly, QIODevice::WriteOnly, or
+    QIODevice::ReadWrite. It may also have additional flags, such as
+    QIODevice::Text and QIODevice::Unbuffered.
+
+    \note In \l{QIODevice::}{WriteOnly} or \l{QIODevice::}{ReadWrite}
+    mode, if the relevant file does not already exist, this function
+    will try to create a new file before opening it.
+
+    \note Because of limitations in the native API, QFile ignores the
+    Unbuffered flag on Windows.
+
+    \sa QIODevice::OpenMode, setFileName()
+*/
+bool QFile::open(OpenMode mode)
+{
+    Q_D(QFile);
+    if (isOpen()) {
+        qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
+        return false;
+    }
+    if (mode & Append)
+        mode |= WriteOnly;
+
+    unsetError();
+    if ((mode & (ReadOnly | WriteOnly)) == 0) {
+        qWarning("QIODevice::open: File access not specified");
+        return false;
+    }
+    if (fileEngine()->open(mode)) {
+        QIODevice::open(mode);
+        if (mode & Append)
+            seek(size());
+        return true;
+    }
+    QFile::FileError err = fileEngine()->error();
+    if(err == QFile::UnspecifiedError)
+        err = QFile::OpenError;
+    d->setError(err, fileEngine()->errorString());
+    return false;
+}
+
+/*! \fn QFile::open(OpenMode, FILE*)
+
+    Use open(FILE *, OpenMode) instead.
+*/
+
+/*!
+    \overload
+
+    Opens the existing file handle \a fh in the given \a mode.
+    Returns true if successful; otherwise returns false.
+
+    Example:
+    \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 3
+
+    When a QFile is opened using this function, close() does not actually
+    close the file, but only flushes it.
+
+    \bold{Warning:}
+    \list 1
+        \o If \a fh is \c stdin, \c stdout, or \c stderr, you may not be able
+           to seek(). See QIODevice::isSequential() for more information.
+        \o Since this function opens the file without specifying the file name,
+           you cannot use this QFile with a QFileInfo.
+    \endlist
+
+    \note For Windows CE you may not be able to call seek() and resize().
+    Also, size() is set to \c 0.
+
+    \sa close(), {qmake Variable Reference#CONFIG}{qmake Variable Reference}
+
+    \bold{Note for the Windows Platform}
+
+    \a fh must be opened in binary mode (i.e., the mode string must contain
+    'b', as in "rb" or "wb") when accessing files and other random-access
+    devices. Qt will translate the end-of-line characters if you pass
+    QIODevice::Text to \a mode. Sequential devices, such as stdin and stdout,
+    are unaffected by this limitation.
+
+    You need to enable support for console applications in order to use the
+    stdin, stdout and stderr streams at the console. To do this, add the
+    following declaration to your application's project file:
+
+    \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 4
+*/
+bool QFile::open(FILE *fh, OpenMode mode)
+{
+    Q_D(QFile);
+    if (isOpen()) {
+        qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
+        return false;
+    }
+    if (mode & Append)
+        mode |= WriteOnly;
+    unsetError();
+    if ((mode & (ReadOnly | WriteOnly)) == 0) {
+        qWarning("QFile::open: File access not specified");
+        return false;
+    }
+    if(d->openExternalFile(mode, fh)) {
+        QIODevice::open(mode);
+        if (mode & Append) {
+            seek(size());
+        } else {
+            long pos = ftell(fh);
+            if (pos != -1)
+                seek(pos);
+        }
+        return true;
+    }
+    return false;
+}
+
+/*! \fn QFile::open(OpenMode, int)
+
+    Use open(int, OpenMode) instead.
+*/
+
+/*!
+    \overload
+
+    Opens the existing file descripter \a fd in the given \a mode.
+    Returns true if successful; otherwise returns false.
+
+    When a QFile is opened using this function, close() does not
+    actually close the file.
+
+    The QFile that is opened using this function is automatically set
+    to be in raw mode; this means that the file input/output functions
+    are slow. If you run into performance issues, you should try to
+    use one of the other open functions.
+
+    \warning If \a fd is 0 (\c stdin), 1 (\c stdout), or 2 (\c
+    stderr), you may not be able to seek(). size() is set to \c
+    LLONG_MAX (in \c <climits>).
+
+    \warning For Windows CE you may not be able to call seek(), setSize(),
+    fileTime(). size() is set to \c 0.
+
+    \warning Since this function opens the file without specifying the file name,
+             you cannot use this QFile with a QFileInfo.
+
+    \sa close()
+*/
+bool QFile::open(int fd, OpenMode mode)
+{
+    Q_D(QFile);
+    if (isOpen()) {
+        qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
+        return false;
+    }
+    if (mode & Append)
+        mode |= WriteOnly;
+    unsetError();
+    if ((mode & (ReadOnly | WriteOnly)) == 0) {
+        qWarning("QFile::open: File access not specified");
+        return false;
+    }
+    if(d->openExternalFile(mode, fd)) {
+        QIODevice::open(mode);
+        if (mode & Append)
+            seek(size());
+        return true;
+    }
+    return false;
+}
+
+/*!
+  Returns the file handle of the file.
+
+  This is a small positive integer, suitable for use with C library
+  functions such as fdopen() and fcntl(). On systems that use file
+  descriptors for sockets (i.e. Unix systems, but not Windows) the handle
+  can be used with QSocketNotifier as well.
+
+  If the file is not open, or there is an error, handle() returns -1.
+
+  This function is not supported on Windows CE.
+
+  \sa QSocketNotifier
+*/
+
+int
+QFile::handle() const
+{
+    if (!isOpen())
+        return -1;
+
+    if (QAbstractFileEngine *engine = fileEngine())
+        return engine->handle();
+    return -1;
+}
+
+/*!
+    \enum QFile::MemoryMapFlags
+    \since 4.4
+
+    This enum describes special options that may be used by the map()
+    function.
+
+    \value NoOptions        No options.
+*/
+
+/*!
+    \since 4.4
+    Maps \a size bytes of the file into memory starting at \a offset.  A file
+    should be open for a map to succeed but the file does not need to stay
+    open after the memory has been mapped.  When the QFile is destroyed
+    or a new file is opened with this object, any maps that have not been
+    unmapped will automatically be unmapped.
+
+    Any mapping options can be passed through \a flags.
+
+    Returns a pointer to the memory or 0 if there is an error.
+
+    \note On Windows CE 5.0 the file will be closed before mapping occurs.
+
+    \sa unmap(), QAbstractFileEngine::supportsExtension()
+ */
+uchar *QFile::map(qint64 offset, qint64 size, MemoryMapFlags flags)
+{
+    Q_D(QFile);
+    QAbstractFileEngine *engine = fileEngine();
+    if (engine
+        && engine->supportsExtension(QAbstractFileEngine::MapExtension)) {
+        unsetError();
+        uchar *address = engine->map(offset, size, flags);
+        if (address == 0)
+            d->setError(engine->error(), engine->errorString());
+        return address;
+    }
+    return 0;
+}
+
+/*!
+    \since 4.4
+    Unmaps the memory \a address.
+
+    Returns true if the unmap succeeds; false otherwise.
+
+    \sa map(), QAbstractFileEngine::supportsExtension()
+ */
+bool QFile::unmap(uchar *address)
+{
+    Q_D(QFile);
+    QAbstractFileEngine *engine = fileEngine();
+    if (engine
+        && engine->supportsExtension(QAbstractFileEngine::UnMapExtension)) {
+        unsetError();
+        bool success = engine->unmap(address);
+        if (!success)
+            d->setError(engine->error(), engine->errorString());
+        return success;
+    }
+    return false;
+}
+
+/*!
+    \fn QString QFile::name() const
+
+    Use fileName() instead.
+*/
+
+/*!
+    \fn void QFile::setName(const QString &name)
+
+    Use setFileName() instead.
+*/
+
+/*!
+    Sets the file size (in bytes) \a sz. Returns true if the file if the
+    resize succeeds; false otherwise. If \a sz is larger than the file
+    currently is the new bytes will be set to 0, if \a sz is smaller the
+    file is simply truncated.
+
+    \sa size(), setFileName()
+*/
+
+bool
+QFile::resize(qint64 sz)
+{
+    Q_D(QFile);
+    if (!d->ensureFlushed())
+        return false;
+    if (isOpen() && fileEngine()->pos() > sz)
+        seek(sz);
+    if(fileEngine()->setSize(sz)) {
+        unsetError();
+        return true;
+    }
+    d->setError(QFile::ResizeError, fileEngine()->errorString());
+    return false;
+}
+
+/*!
+    \overload
+
+    Sets \a fileName to size (in bytes) \a sz. Returns true if the file if
+    the resize succeeds; false otherwise. If \a sz is larger than \a
+    fileName currently is the new bytes will be set to 0, if \a sz is
+    smaller the file is simply truncated.
+
+    \sa resize()
+*/
+
+bool
+QFile::resize(const QString &fileName, qint64 sz)
+{
+    return QFile(fileName).resize(sz);
+}
+
+/*!
+    Returns the complete OR-ed together combination of
+    QFile::Permission for the file.
+
+    \sa setPermissions(), setFileName()
+*/
+
+QFile::Permissions
+QFile::permissions() const
+{
+    QAbstractFileEngine::FileFlags perms = fileEngine()->fileFlags(QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask;
+    return QFile::Permissions((int)perms); //ewww
+}
+
+/*!
+    \overload
+
+    Returns the complete OR-ed together combination of
+    QFile::Permission for \a fileName.
+*/
+
+QFile::Permissions
+QFile::permissions(const QString &fileName)
+{
+    return QFile(fileName).permissions();
+}
+
+/*!
+    Sets the permissions for the file to the \a permissions specified.
+    Returns true if successful, or false if the permissions cannot be
+    modified.
+
+    \sa permissions(), setFileName()
+*/
+
+bool
+QFile::setPermissions(Permissions permissions)
+{
+    Q_D(QFile);
+    if(fileEngine()->setPermissions(permissions)) {
+        unsetError();
+        return true;
+    }
+    d->setError(QFile::PermissionsError, fileEngine()->errorString());
+    return false;
+}
+
+/*!
+    \overload
+
+    Sets the permissions for \a fileName file to \a permissions.
+*/
+
+bool
+QFile::setPermissions(const QString &fileName, Permissions permissions)
+{
+    return QFile(fileName).setPermissions(permissions);
+}
+
+static inline qint64 _qfile_writeData(QAbstractFileEngine *engine, QRingBuffer *buffer)
+{
+    qint64 ret = engine->write(buffer->readPointer(), buffer->size());
+    if (ret > 0)
+        buffer->free(ret);
+    return ret;
+}
+
+/*!
+    Flushes any buffered data to the file. Returns true if successful;
+    otherwise returns false.
+*/
+
+bool
+QFile::flush()
+{
+    Q_D(QFile);
+    if (!d->writeBuffer.isEmpty()) {
+        qint64 size = d->writeBuffer.size();
+        if (_qfile_writeData(d->fileEngine ? d->fileEngine : fileEngine(),
+                             &d->writeBuffer) != size) {
+            QFile::FileError err = fileEngine()->error();
+            if(err == QFile::UnspecifiedError)
+                err = QFile::WriteError;
+            d->setError(err, fileEngine()->errorString());
+            return false;
+        }
+    }
+
+    if (!fileEngine()->flush()) {
+        QFile::FileError err = fileEngine()->error();
+        if(err == QFile::UnspecifiedError)
+            err = QFile::WriteError;
+        d->setError(err, fileEngine()->errorString());
+        return false;
+    }
+    return true;
+}
+
+/*!
+  Calls QFile::flush() and closes the file. Errors from flush are ignored.
+
+  \sa QIODevice::close()
+*/
+void
+QFile::close()
+{
+    Q_D(QFile);
+    if(!isOpen())
+        return;
+    flush();
+    QIODevice::close();
+
+    unsetError();
+    if(!fileEngine()->close())
+        d->setError(fileEngine()->error(), fileEngine()->errorString());
+}
+
+/*!
+  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().
+*/
+
+qint64 QFile::size() const
+{
+    Q_D(const QFile);
+    if (!d->ensureFlushed())
+        return 0;
+    return fileEngine()->size();
+}
+
+/*!
+  \reimp
+*/
+
+qint64 QFile::pos() const
+{
+    return QIODevice::pos();
+}
+
+/*!
+  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.
+*/
+
+bool QFile::atEnd() const
+{
+    Q_D(const QFile);
+
+    if (!isOpen())
+        return true;
+
+    if (!d->ensureFlushed())
+        return false;
+
+    // If there's buffered data left, we're not at the end.
+    if (!d->buffer.isEmpty())
+        return false;
+
+    // If the file engine knows best, say what it says.
+    if (fileEngine()->supportsExtension(QAbstractFileEngine::AtEndExtension)) {
+        // Check if the file engine supports AtEndExtension, and if it does,
+        // check if the file engine claims to be at the end.
+        return fileEngine()->atEnd();
+    }
+
+    // Fall back to checking how much is available (will stat files).
+    return bytesAvailable() == 0;
+}
+
+/*!
+  \reimp
+*/
+
+bool QFile::seek(qint64 off)
+{
+    Q_D(QFile);
+    if (!isOpen()) {
+        qWarning("QFile::seek: IODevice is not open");
+        return false;
+    }
+
+    if (!d->ensureFlushed())
+        return false;
+
+    if (!fileEngine()->seek(off) || !QIODevice::seek(off)) {
+        QFile::FileError err = fileEngine()->error();
+        if(err == QFile::UnspecifiedError)
+            err = QFile::PositionError;
+        d->setError(err, fileEngine()->errorString());
+        return false;
+    }
+    unsetError();
+    return true;
+}
+
+/*!
+  \reimp
+*/
+qint64 QFile::readLineData(char *data, qint64 maxlen)
+{
+    Q_D(QFile);
+    if (!d->ensureFlushed())
+        return -1;
+
+    if (fileEngine()->supportsExtension(QAbstractFileEngine::FastReadLineExtension))
+        return fileEngine()->readLine(data, maxlen);
+
+    // Fall back to QIODevice's readLine implementation if the engine
+    // cannot do it faster.
+    return QIODevice::readLineData(data, maxlen);
+}
+
+/*!
+  \reimp
+*/
+
+qint64 QFile::readData(char *data, qint64 len)
+{
+    Q_D(QFile);
+    unsetError();
+    if (!d->ensureFlushed())
+        return -1;
+
+    qint64 ret = -1;
+    qint64 read = fileEngine()->read(data, len);
+    if (read != -1)
+        ret = read;
+
+    if(ret < 0) {
+        QFile::FileError err = fileEngine()->error();
+        if(err == QFile::UnspecifiedError)
+            err = QFile::ReadError;
+        d->setError(err, fileEngine()->errorString());
+    }
+    return ret;
+}
+
+/*!
+    \internal
+*/
+bool QFilePrivate::putCharHelper(char c)
+{
+#ifdef QT_NO_QOBJECT
+    return QIODevicePrivate::putCharHelper(c);
+#else
+
+    // Cutoff for code that doesn't only touch the buffer.
+    int writeBufferSize = writeBuffer.size();
+    if ((openMode & QIODevice::Unbuffered) || writeBufferSize + 1 >= QFILE_WRITEBUFFER_SIZE
+#ifdef Q_OS_WIN
+        || ((openMode & QIODevice::Text) && c == '\n' && writeBufferSize + 2 >= QFILE_WRITEBUFFER_SIZE)
+#endif
+        ) {
+        return QIODevicePrivate::putCharHelper(c);
+    }
+
+    if (!(openMode & QIODevice::WriteOnly)) {
+        if (openMode == QIODevice::NotOpen)
+            qWarning("QIODevice::putChar: Closed device");
+        else
+            qWarning("QIODevice::putChar: ReadOnly device");
+        return false;
+    }
+
+    // Make sure the device is positioned correctly.
+    const bool sequential = isSequential();
+    if (pos != devicePos && !sequential && !q_func()->seek(pos))
+        return false;
+
+    lastWasWrite = true;
+
+    int len = 1;
+#ifdef Q_OS_WIN
+    if ((openMode & QIODevice::Text) && c == '\n') {
+        ++len;
+        *writeBuffer.reserve(1) = '\r';
+    }
+#endif
+
+    // Write to buffer.
+    *writeBuffer.reserve(1) = c;
+
+    if (!sequential) {
+        pos += len;
+        devicePos += len;
+        if (!buffer.isEmpty())
+            buffer.skip(len);
+    }
+
+    return true;
+#endif
+}
+
+/*!
+  \reimp
+*/
+
+qint64
+QFile::writeData(const char *data, qint64 len)
+{
+    Q_D(QFile);
+    unsetError();
+    d->lastWasWrite = true;
+    bool buffered = !(d->openMode & Unbuffered);
+
+    // Flush buffered data if this read will overflow.
+    if (buffered && (d->writeBuffer.size() + len) > QFILE_WRITEBUFFER_SIZE) {
+        if (!flush())
+            return -1;
+    }
+
+    // Write directly to the engine if the block size is larger than
+    // the write buffer size.
+    if (!buffered || len > QFILE_WRITEBUFFER_SIZE) {
+        QAbstractFileEngine *fe = d->fileEngine ? d->fileEngine : fileEngine();
+        qint64 ret = fe->write(data, len);
+        if(ret < 0) {
+            QFile::FileError err = fileEngine()->error();
+            if(err == QFile::UnspecifiedError)
+                err = QFile::WriteError;
+            d->setError(err, fileEngine()->errorString());
+        }
+        return ret;
+    }
+
+    // Write to the buffer.
+    char *writePointer = d->writeBuffer.reserve(len);
+    if (len == 1)
+        *writePointer = *data;
+    else
+        ::memcpy(writePointer, data, len);
+    return len;
+}
+
+/*!
+    \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;
+}
+
+/*!
+    Returns the file error status.
+
+    The I/O device status returns an error code. For example, if open()
+    returns false, or a read/write operation returns -1, this function can
+    be called to find out the reason why the operation failed.
+
+    \sa unsetError()
+*/
+
+QFile::FileError
+QFile::error() const
+{
+    Q_D(const QFile);
+    return d->error;
+}
+
+/*!
+    Sets the file's error to QFile::NoError.
+
+    \sa error()
+*/
+void
+QFile::unsetError()
+{
+    Q_D(QFile);
+    d->setError(QFile::NoError);
+}
+
+QT_END_NAMESPACE