/*! Opens the file descriptor \a fd to the file engine, using the open mode \a flags. */ bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd) { Q_Q(QFSFileEngine); this->fd = fd; fh = 0; // Seek to the end when in Append mode. if (openMode & QFile::Append) { int ret; do { ret = QT_LSEEK(fd, 0, SEEK_END); } while (ret == -1 && errno == EINTR); if (ret == -1) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); this->openMode = QIODevice::NotOpen; this->fd = -1; return false; } } return true; }
/*! \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; }
/*! \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; }
/*! \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; }
/*! \internal */ qint64 QFSFileEnginePrivate::posFdFh() const { if (fh) return qint64(QT_FTELL(fh)); return QT_LSEEK(fd, 0, SEEK_CUR); }
/*! \internal */ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) { Q_Q(QFSFileEngine); if (openMode & QIODevice::Unbuffered) { int flags = openModeToOpenFlags(openMode); // Try to open the file in unbuffered mode. do { fd = QT_OPEN(nativeFilePath.constData(), flags, 0666); } while (fd == -1 && errno == EINTR); // On failure, return and report the error. if (fd == -1) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(errno)); return false; } #ifndef O_CLOEXEC // not needed on Linux >= 2.6.23 setCloseOnExec(fd); // ignore failure #endif // Seek to the end when in Append mode. if (flags & QFile::Append) { int ret; do { ret = QT_LSEEK(fd, 0, SEEK_END); } while (ret == -1 && errno == EINTR); if (ret == -1) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); return false; } } fh = 0; } else { QByteArray fopenMode = openModeToFopenMode(openMode, filePath); // Try to open the file in buffered mode. do { fh = QT_FOPEN(nativeFilePath.constData(), fopenMode.constData()); } while (!fh && errno == EINTR); // On failure, return and report the error. if (!fh) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); return false; } setCloseOnExec(fileno(fh)); // ignore failure // Seek to the end when in Append mode. if (openMode & QIODevice::Append) { int ret; do { ret = QT_FSEEK(fh, 0, SEEK_END); } while (ret == -1 && errno == EINTR); if (ret == -1) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); return false; } } fd = -1; } closeFileHandle = true; return true; }
/*! \internal */ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) { Q_Q(QFSFileEngine); if (openMode & QIODevice::Unbuffered) { int flags = openModeToOpenFlags(openMode); // Try to open the file in unbuffered mode. do { fd = QT_OPEN(fileEntry.nativeFilePath().constData(), flags, 0666); } while (fd == -1 && errno == EINTR); // On failure, return and report the error. if (fd == -1) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(errno)); return false; } if (!(openMode & QIODevice::WriteOnly)) { // we don't need this check if we tried to open for writing because then // we had received EISDIR anyway. if (QFileSystemEngine::fillMetaData(fd, metaData) && metaData.isDirectory()) { q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); QT_CLOSE(fd); return false; } } // Seek to the end when in Append mode. if (flags & QFile::Append) { int ret; do { ret = QT_LSEEK(fd, 0, SEEK_END); } while (ret == -1 && errno == EINTR); if (ret == -1) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); return false; } } fh = 0; } else { QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry, metaData); // Try to open the file in buffered mode. do { fh = QT_FOPEN(fileEntry.nativeFilePath().constData(), fopenMode.constData()); } while (!fh && errno == EINTR); // On failure, return and report the error. if (!fh) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); return false; } if (!(openMode & QIODevice::WriteOnly)) { // we don't need this check if we tried to open for writing because then // we had received EISDIR anyway. if (QFileSystemEngine::fillMetaData(QT_FILENO(fh), metaData) && metaData.isDirectory()) { q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); fclose(fh); return false; } } setCloseOnExec(fileno(fh)); // ignore failure // Seek to the end when in Append mode. if (openMode & QIODevice::Append) { int ret; do { ret = QT_FSEEK(fh, 0, SEEK_END); } while (ret == -1 && errno == EINTR); if (ret == -1) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); return false; } } fd = -1; } closeFileHandle = true; return true; }