Beispiel #1
0
bool MyFile::copy(const QString &newName)
{
    if (fileName().isEmpty()) {
        qWarning("QFile::copy: Empty or null file name");
        return false;
    }
    if (QFile(newName).exists())
        return false;
    unsetError();
    close();
    if(error() == QFile::NoError) {
        bool error = false;
        if(!open(QFile::ReadOnly)) {
            error = true;
        } else {
            QFile out(newName);
            if (!out.open(QIODevice::ReadWrite))
                error = true;
            if (error) {
                out.close();
                close();
            } 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)) {
                        close();
                        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.remove();
            }
        }
        if(!error) {
            QFile::setPermissions(newName, permissions());
            close();
            unsetError();
            return true;
        }
    }
    return false;
}
Beispiel #2
0
/*!
    \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::isSequentialAccess() 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;
}
Beispiel #3
0
/*!
    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;
}
Beispiel #4
0
/*!
    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.

    \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;
    }

    // QIODevice provides the buffering, so there's no need to request it from the file engine.
    if (fileEngine()->open(mode | QIODevice::Unbuffered)) {
        QIODevice::open(mode);
        if (mode & Append)
            seek(size());
        return true;
    }
    QFile::FileError err = d->fileEngine->error();
    if(err == QFile::UnspecifiedError)
        err = QFile::OpenError;
    d->setError(err, d->fileEngine->errorString());
    return false;
}
Beispiel #5
0
/*!
  \reimp
*/
qint64 QFileDevice::writeData(const char *data, qint64 len)
{
    Q_D(QFileDevice);
    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) {
        const qint64 ret = d->fileEngine->write(data, len);
        if (ret < 0) {
            QFileDevice::FileError err = d->fileEngine->error();
            if (err == QFileDevice::UnspecifiedError)
                err = QFileDevice::WriteError;
            d->setError(err, d->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;
}
Beispiel #6
0
/*!
    \overload

    Opens the existing file descriptor \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 not a regular file, e.g, it is 0 (\c stdin),
    1 (\c stdout), or 2 (\c stderr), you may not be able to seek(). In
    those cases, size() returns \c 0.  See QIODevice::isSequential()
    for more information.

    \warning For Windows CE you may not be able to call seek(), setSize(),
    fileTime(). size() returns \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());
        } else {
            qint64 pos = (qint64)QT_LSEEK(fd, QT_OFF_T(0), SEEK_CUR);
            if (pos != -1)
                seek(pos);
        }
        return true;
    }
    return false;
}
Beispiel #7
0
/*!
    \overload

    Opens the existing file descriptor \a fd in the given \a mode.
    \a handleFlags may be used to specify additional options.
    Returns true if successful; otherwise returns false.

    When a QFile is opened using this function, behaviour of close() is
    controlled by the AutoCloseHandle flag.
    If AutoCloseHandle is specified, and this function succeeds,
    then calling close() closes the adopted handle.
    Otherwise, close() does not actually close the file, but only flushes it.

    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 not a regular file, e.g, it is 0 (\c stdin),
    1 (\c stdout), or 2 (\c stderr), you may not be able to seek(). In
    those cases, size() returns \c 0.  See QIODevice::isSequential()
    for more information.

    \warning For Windows CE you may not be able to call seek(), setSize(),
    fileTime(). size() returns \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, FileHandleFlags handleFlags)
{
    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, handleFlags)) {
        QIODevice::open(mode);
        if (!(mode & Append) && !isSequential()) {
            qint64 pos = (qint64)QT_LSEEK(fd, QT_OFF_T(0), SEEK_CUR);
            if (pos != -1) {
                // Skip redundant checks in QFileDevice::seek().
                QIODevice::seek(pos);
            }
        }
        return true;
    }
    return false;
}
Beispiel #8
0
bool
QFile::remove()
{
    Q_D(QFile);
    if (d->fileName.isEmpty()) {
        qWarning("QFile::remove: Empty or null file name");
        return false;
    }
    unsetError();
    close();
    if(error() == QFile::NoError) {
        if(fileEngine()->remove()) {
            unsetError();
            return true;
        }
        d->setError(QFile::RemoveError, d->fileEngine->errorString());
    }
    return false;
}
Beispiel #9
0
/*!
    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()
*/
bool QFileDevice::setPermissions(Permissions permissions)
{
    Q_D(QFileDevice);
    if (d->engine()->setPermissions(permissions)) {
        unsetError();
        return true;
    }
    d->setError(QFile::PermissionsError, d->fileEngine->errorString());
    return false;
}
Beispiel #10
0
bool
QFile::setPermissions(Permissions permissions)
{
    Q_D(QFile);
    if(fileEngine()->setPermissions(permissions)) {
        unsetError();
        return true;
    }
    d->setError(QFile::PermissionsError, errno);
    return false;
}
Beispiel #11
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);
    if (fileEngine()
        && d->fileEngine->supportsExtension(QAbstractFileEngine::UnMapExtension)) {
        unsetError();
        bool success = d->fileEngine->unmap(address);
        if (!success)
            d->setError(d->fileEngine->error(), d->fileEngine->errorString());
        return success;
    }
    return false;
}
Beispiel #12
0
/*!
    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()
 */
uchar *QFileDevice::map(qint64 offset, qint64 size, MemoryMapFlags flags)
{
    Q_D(QFileDevice);
    if (d->engine()
            && d->fileEngine->supportsExtension(QAbstractFileEngine::MapExtension)) {
        unsetError();
        uchar *address = d->fileEngine->map(offset, size, flags);
        if (address == 0)
            d->setError(d->fileEngine->error(), d->fileEngine->errorString());
        return address;
    }
    return 0;
}
Beispiel #13
0
void
QFile::close()
{
    Q_D(QFile);
    if(!isOpen())
        return;
    flush();
    QIODevice::close();

    unsetError();
    if(!fileEngine()->close())
        d->setError(fileEngine()->error(), fileEngine()->errorString());
}
Beispiel #14
0
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, QLatin1String("Destination file exists"));
        return false;
    }
    close();
    if(error() == QFile::NoError) {
        if (fileEngine()->rename(newName)) {
            unsetError();
            return true;
        }

        QFile in(fileName());
        QFile out(newName);
        if (in.open(QIODevice::ReadOnly)) {
            if (out.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
                bool error = false;
                char block[4096];
                while (!in.atEnd()) {
                    qint64 read = in.read(block, sizeof(block));
                    if (read == -1) {
                        d->setError(QFile::RenameError, in.errorString());
                        error = true;
                        break;
                    }
                    if (read != out.write(block, read)) {
                        d->setError(QFile::RenameError, out.errorString());
                        error = true;
                        break;
                    }
                }
                if(!error)
                    in.remove();
                return !error;
            }
        }
        d->setError(QFile::RenameError, out.isOpen() ? in.errorString() : out.errorString());
    }
    return false;
}
Beispiel #15
0
/*!
    Unmaps the memory \a address.

    Returns true if the unmap succeeds; false otherwise.

    \sa map()
 */
bool QFileDevice::unmap(uchar *address)
{
    Q_D(QFileDevice);
    if (d->engine()
        && d->fileEngine->supportsExtension(QAbstractFileEngine::UnMapExtension)) {
        unsetError();
        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;
}
Beispiel #16
0
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, errno);
    return false;
}
Beispiel #17
0
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, errno);
    return false;
}
Beispiel #18
0
/*!
    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()
*/
bool QFileDevice::resize(qint64 sz)
{
    Q_D(QFileDevice);
    if (!d->ensureFlushed())
        return false;
    d->engine();
    if (isOpen() && d->fileEngine->pos() > sz)
        seek(sz);
    if (d->fileEngine->setSize(sz)) {
        unsetError();
        d->cachedSize = sz;
        return true;
    }
    d->cachedSize = 0;
    d->setError(QFile::ResizeError, d->fileEngine->errorString());
    return false;
}
Beispiel #19
0
/*!
  Calls QFileDevice::flush() and closes the file. Errors from flush are ignored.

  \sa QIODevice::close()
*/
void QFileDevice::close()
{
    Q_D(QFileDevice);
    if (!isOpen())
        return;
    bool flushed = flush();
    QIODevice::close();

    // reset write buffer
    d->lastWasWrite = false;
    d->writeBuffer.clear();

    // keep earlier error from flush
    if (d->fileEngine->close() && flushed)
        unsetError();
    else if (flushed)
        d->setError(d->fileEngine->error(), d->fileEngine->errorString());
}
Beispiel #20
0
/*!
    \fn bool QFileDevice::seek(qint64 pos)

    For random-access devices, this function sets the current position
    to \a pos, returning true on success, or false if an error occurred.
    For sequential devices, the default behavior is to do nothing and
    return false.

    Seeking beyond the end of a file:
    If the position is beyond the end of a file, then seek() shall not
    immediately extend the file. If a write is performed at this position,
    then the file shall be extended. The content of the file between the
    previous end of file and the newly written data is UNDEFINED and
    varies between platforms and file systems.
*/
bool QFileDevice::seek(qint64 off)
{
    Q_D(QFileDevice);
    if (!isOpen()) {
        qWarning("QFileDevice::seek: IODevice is not open");
        return false;
    }

    if (!d->ensureFlushed())
        return false;

    if (!d->fileEngine->seek(off) || !QIODevice::seek(off)) {
        QFileDevice::FileError err = d->fileEngine->error();
        if (err == QFileDevice::UnspecifiedError)
            err = QFileDevice::PositionError;
        d->setError(err, d->fileEngine->errorString());
        return false;
    }
    unsetError();
    return true;
}
Beispiel #21
0
qint64 QFile::readData(char *data, qint64 len)
{
    Q_D(QFile);
    unsetError();
    if (!d->ensureFlushed())
        return -1;

    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 (read < len) {
        // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
        d->cachedSize = 0;
    }

    return read;
}
Beispiel #22
0
/*!
    \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;
}
Beispiel #23
0
bool QFile::seek(qint64 off)
{
    Q_D(QFile);
    if (!isOpen()) {
        qWarning("QFile::seek: IODevice is not open");
        return false;
    }

    if (off == d->pos && off == d->devicePos)
        return true; //avoid expensive flush for NOP seek to current position

    if (!d->ensureFlushed())
        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());
        return false;
    }
    unsetError();
    return true;
}
Beispiel #24
0
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
            d->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 {
                    d->fileEngine->setFileName(newName);
                    setPermissions(permissions());
                    unsetError();
                    setFileName(newName);
                }
                close();
                return !error;
            }
            close();
        }
        d->setError(QFile::RenameError, out.isOpen() ? errorString() : out.errorString());
    }
    return false;
}
Beispiel #25
0
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, QLatin1String("Destination file exists"));
        return false;
    }
    close();
    if(error() == QFile::NoError) {
        if(fileEngine()->copy(newName)) {
            unsetError();
            return true;
        } else {
            bool error = false;
            if(!open(QFile::ReadOnly)) {
                error = true;
                QString errorMessage = QLatin1String("Cannot open %1 for input");
                d->setError(QFile::CopyError, errorMessage.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, QLatin1String("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, QLatin1String("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;
                        QString errorMessage = QLatin1String("Cannot create %1 for output");
                        d->setError(QFile::CopyError, errorMessage.arg(newName));
                    }
#ifndef QT_NO_TEMPORARYFILE
                    if (!error)
                        out.setAutoRemove(false);
#endif
                }
            }
            if(!error) {
                QFile::setPermissions(newName, permissions());
                unsetError();
                return true;
            }
        }
    }
    return false;
}
Beispiel #26
0
/*!
    Opens the file using OpenMode \a mode, returning true if successful;
    otherwise false.

    Important: the \a mode must include QIODevice::WriteOnly.
    It may also have additional flags, such as QIODevice::Text and QIODevice::Unbuffered.

    QIODevice::ReadWrite and QIODevice::Append are not supported at the moment.

    \sa QIODevice::OpenMode, setFileName()
*/
bool QSaveFile::open(OpenMode mode)
{
    Q_D(QSaveFile);
    if (isOpen()) {
        qWarning("QSaveFile::open: File (%s) already open", qPrintable(fileName()));
        return false;
    }
    unsetError();
    if ((mode & (ReadOnly | WriteOnly)) == 0) {
        qWarning("QSaveFile::open: Open mode not specified");
        return false;
    }
    // In the future we could implement ReadWrite by copying from the existing file to the temp file...
    if ((mode & ReadOnly) || (mode & Append)) {
        qWarning("QSaveFile::open: Unsupported open mode 0x%x", int(mode));
        return false;
    }

    // check if existing file is writable
    QFileInfo existingFile(d->fileName);
    if (existingFile.exists() && !existingFile.isWritable()) {
        d->setError(QFileDevice::WriteError, QSaveFile::tr("Existing file %1 is not writable").arg(d->fileName));
        d->writeError = QFileDevice::WriteError;
        return false;
    }

    if (existingFile.isDir()) {
        d->setError(QFileDevice::WriteError, QSaveFile::tr("Filename refers to a directory"));
        d->writeError = QFileDevice::WriteError;
        return false;
    }

    // Resolve symlinks. Don't use QFileInfo::canonicalFilePath so it still give the expected
    // target even if the file does not exist
    d->finalFileName = d->fileName;
    if (existingFile.isSymLink()) {
        int maxDepth = 128;
        while (--maxDepth && existingFile.isSymLink())
            existingFile.setFile(existingFile.symLinkTarget());
        if (maxDepth > 0)
            d->finalFileName = existingFile.filePath();
    }

    d->fileEngine = new QTemporaryFileEngine;
    static_cast<QTemporaryFileEngine *>(d->fileEngine)->initialize(d->finalFileName, 0666);
    // Same as in QFile: QIODevice provides the buffering, so there's no need to request it from the file engine.
    if (!d->fileEngine->open(mode | QIODevice::Unbuffered)) {
        QFileDevice::FileError err = d->fileEngine->error();
#ifdef Q_OS_UNIX
        if (d->directWriteFallback && err == QFileDevice::OpenError && errno == EACCES) {
            delete d->fileEngine;
            d->fileEngine = QAbstractFileEngine::create(d->finalFileName);
            if (d->fileEngine->open(mode | QIODevice::Unbuffered)) {
                d->useTemporaryFile = false;
                QFileDevice::open(mode);
                return true;
            }
            err = d->fileEngine->error();
        }
#endif
        if (err == QFileDevice::UnspecifiedError)
            err = QFileDevice::OpenError;
        d->setError(err, d->fileEngine->errorString());
        delete d->fileEngine;
        d->fileEngine = 0;
        return false;
    }

    d->useTemporaryFile = true;
    QFileDevice::open(mode);
    if (existingFile.exists())
        setPermissions(existingFile.permissions());
    return true;
}
Beispiel #27
0
bool
QFile::rename(const QString &newName)
{
    Q_D(QFile);
    if (d->fileName.isEmpty()) {
        qWarning("QFile::rename: Empty or null file name");
        return false;
    }
    if (d->fileName == newName) {
        d->setError(QFile::RenameError, tr("Destination file is the same file."));
        return false;
    }
    if (!exists()) {
        d->setError(QFile::RenameError, tr("Source file does not exist."));
        return false;
    }
    // If the file exists and it is a case-changing rename ("foo" -> "Foo"),
    // compare Ids to make sure it really is a different file.
    if (QFile::exists(newName)) {
        if (d->fileName.compare(newName, Qt::CaseInsensitive)
            || QFileSystemEngine::id(QFileSystemEntry(d->fileName)) != QFileSystemEngine::id(QFileSystemEntry(newName))) {
            // ### 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;
        }
#ifndef QT_NO_TEMPORARYFILE
        // This #ifndef disables the workaround it encloses. Therefore, this configuration is not recommended.
#ifdef Q_OS_LINUX
        // rename() on Linux simply does nothing when renaming "foo" to "Foo" on a case-insensitive
        // FS, such as FAT32. Move the file away and rename in 2 steps to work around.
        QTemporaryFile tempFile(d->fileName + QStringLiteral(".XXXXXX"));
        tempFile.setAutoRemove(false);
        if (!tempFile.open(QIODevice::ReadWrite)) {
            d->setError(QFile::RenameError, tempFile.errorString());
            return false;
        }
        tempFile.close();
        if (!d->engine()->rename(tempFile.fileName())) {
            d->setError(QFile::RenameError, tr("Error while renaming."));
            return false;
        }
        if (tempFile.rename(newName)) {
            d->fileEngine->setFileName(newName);
            d->fileName = newName;
            return true;
        }
        d->setError(QFile::RenameError, tempFile.errorString());
        // We need to restore the original file.
        if (!tempFile.rename(d->fileName)) {
            d->setError(QFile::RenameError, errorString() + QLatin1Char('\n')
                        + tr("Unable to restore from %1: %2").
                        arg(QDir::toNativeSeparators(tempFile.fileName()), tempFile.errorString()));
        }
        return false;
#endif // Q_OS_LINUX
#endif // QT_NO_TEMPORARYFILE
    }
    unsetError();
    close();
    if(error() == QFile::NoError) {
        if (d->engine()->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;
        }

        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 {
                    d->fileEngine->setFileName(newName);
                    setPermissions(permissions());
                    unsetError();
                    setFileName(newName);
                }
                close();
                return !error;
            }
            close();
        }
        d->setError(QFile::RenameError, out.isOpen() ? errorString() : out.errorString());
    }
    return false;
}