/*!
    \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 (pos < 0 || pos != qint64(QT_OFF_T(pos)))
        return false;

    if (fh) {
        // Buffered stdlib mode.
        int ret;
        do {
            ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET);
        } while (ret != 0 && errno == EINTR);

        if (ret != 0) {
            q->setError(QFile::ReadError, qt_error_string(int(errno)));
            return false;
        }
    } else {
        // Unbuffered stdio mode.
        if (QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) {
            qWarning() << "QFile::at: Cannot set file position" << pos;
            q->setError(QFile::PositionError, qt_error_string(errno));
            return false;
        }
    }
    return true;
}
Exemple #2
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;
}
Exemple #3
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;
}
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
{
    Q_Q(QFSFileEngine);
    Q_UNUSED(flags);
    if (openMode == QIODevice::NotOpen) {
        q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
        return 0;
    }

    if (offset < 0 || offset != qint64(QT_OFF_T(offset))
            || size < 0 || quint64(size) > quint64(size_t(-1))) {
        q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
        return 0;
    }

    // If we know the mapping will extend beyond EOF, fail early to avoid
    // undefined behavior. Otherwise, let mmap have its say.
    if (doStat(QFileSystemMetaData::SizeAttribute)
            && (QT_OFF_T(size) > metaData.size() - QT_OFF_T(offset)))
        qWarning("QFSFileEngine::map: Mapping a file beyond its size is not portable");

    int access = 0;
    if (openMode & QIODevice::ReadOnly) access |= PROT_READ;
    if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE;

#if defined(Q_OS_INTEGRITY)
    int pageSize = sysconf(_SC_PAGESIZE);
#else
    int pageSize = getpagesize();
#endif
    int extra = offset % pageSize;

    if (quint64(size + extra) > quint64((size_t)-1)) {
        q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
        return 0;
    }

    size_t realSize = (size_t)size + extra;
    QT_OFF_T realOffset = QT_OFF_T(offset);
    realOffset &= ~(QT_OFF_T(pageSize - 1));

#ifdef QT_SYMBIAN_USE_NATIVE_FILEMAP
    TInt nativeMapError = KErrNone;
    RFileMap mapping;
    TUint mode(EFileMapRemovableMedia);
    TUint64 nativeOffset = offset & ~(mapping.PageSizeInBytes() - 1);

    //If the file was opened for write or read/write, then open the map for read/write
    if (openMode & QIODevice::WriteOnly)
        mode |= EFileMapWrite;
    if (symbianFile.SubSessionHandle()) {
        nativeMapError = mapping.Open(symbianFile, nativeOffset, size, mode);
    } else {
        //map file by name if we don't have a native handle
        QString fn = QFileSystemEngine::absoluteName(fileEntry).nativeFilePath();
        TUint filemode = EFileShareReadersOrWriters | EFileRead;
        if (openMode & QIODevice::WriteOnly)
            filemode |= EFileWrite;
        nativeMapError = mapping.Open(qt_s60GetRFs(), qt_QString2TPtrC(fn), filemode, nativeOffset, size, mode);
    }
    if (nativeMapError == KErrNone) {
        QScopedResource<RFileMap> ptr(mapping); //will call Close if adding to mapping throws an exception
        uchar *address = mapping.Base() + (offset - nativeOffset);
        maps[address] = mapping;
        ptr.take();
        return address;
    }
    QFile::FileError reportedError = QFile::UnspecifiedError;
    switch (nativeMapError) {
    case KErrAccessDenied:
    case KErrPermissionDenied:
        reportedError = QFile::PermissionsError;
        break;
    case KErrNoMemory:
        reportedError = QFile::ResourceError;
        break;
    }
    q->setError(reportedError, QSystemError(nativeMapError, QSystemError::NativeError).toString());
    return 0;
#else
#ifdef Q_OS_SYMBIAN
    //older phones & emulator don't support native mapping, so need to keep the open C way around for those.
    void *mapAddress;
    TRAPD(err, mapAddress = QT_MMAP((void*)0, realSize,
                   access, MAP_SHARED, getMapHandle(), realOffset));
    if (err != KErrNone) {
        qWarning("OpenC bug: leave from mmap %d", err);
        mapAddress = MAP_FAILED;
        errno = EINVAL;
    }
#else
    void *mapAddress = QT_MMAP((void*)0, realSize,
                   access, MAP_SHARED, nativeHandle(), realOffset);
#endif
    if (MAP_FAILED != mapAddress) {
        uchar *address = extra + static_cast<uchar*>(mapAddress);
        maps[address] = QPair<int,size_t>(extra, realSize);
        return address;
    }

    switch(errno) {
    case EBADF:
        q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
        break;
    case ENFILE:
    case ENOMEM:
        q->setError(QFile::ResourceError, qt_error_string(int(errno)));
        break;
    case EINVAL:
        // size are out of bounds
    default:
        q->setError(QFile::UnspecifiedError, qt_error_string(int(errno)));
        break;
    }
    return 0;
#endif
}
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
{
    Q_Q(QFSFileEngine);
    Q_UNUSED(flags);
    if (openMode == QIODevice::NotOpen) {
        q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
        return 0;
    }

    if (offset < 0 || offset != qint64(QT_OFF_T(offset))
            || size < 0 || quint64(size) > quint64(size_t(-1))) {
        q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
        return 0;
    }

    // If we know the mapping will extend beyond EOF, fail early to avoid
    // undefined behavior. Otherwise, let mmap have its say.
    if (doStat(QFileSystemMetaData::SizeAttribute)
            && (QT_OFF_T(size) > metaData.size() - QT_OFF_T(offset)))
        qWarning("QFSFileEngine::map: Mapping a file beyond its size is not portable");

    int access = 0;
    if (openMode & QIODevice::ReadOnly) access |= PROT_READ;
    if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE;

    int sharemode = MAP_SHARED;
    if (flags & QFileDevice::MapPrivateOption) {
        sharemode = MAP_PRIVATE;
        access |= PROT_WRITE;
    }

#if defined(Q_OS_INTEGRITY)
    int pageSize = sysconf(_SC_PAGESIZE);
#else
    int pageSize = getpagesize();
#endif
    int extra = offset % pageSize;

    if (quint64(size + extra) > quint64((size_t)-1)) {
        q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
        return 0;
    }

    size_t realSize = (size_t)size + extra;
    QT_OFF_T realOffset = QT_OFF_T(offset);
    realOffset &= ~(QT_OFF_T(pageSize - 1));

    void *mapAddress = QT_MMAP((void*)0, realSize,
                   access, sharemode, nativeHandle(), realOffset);
    if (MAP_FAILED != mapAddress) {
        uchar *address = extra + static_cast<uchar*>(mapAddress);
        maps[address] = QPair<int,size_t>(extra, realSize);
        return address;
    }

    switch(errno) {
    case EBADF:
        q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
        break;
    case ENFILE:
    case ENOMEM:
        q->setError(QFile::ResourceError, qt_error_string(int(errno)));
        break;
    case EINVAL:
        // size are out of bounds
    default:
        q->setError(QFile::UnspecifiedError, qt_error_string(int(errno)));
        break;
    }
    return 0;
}