diff --git a/src/core/filejob.h b/src/core/filejob.h --- a/src/core/filejob.h +++ b/src/core/filejob.h @@ -45,31 +45,55 @@ ~FileJob(); /** - * Read block + * This function attempts to read up to \p size bytes from the URL passed to + * KIO::open() and returns the bytes received via the data() signal. + * + * The read operation commences at the current file offset, and the file + * offset is incremented by the number of bytes read, but this change in the + * offset does not result in the position() signal being emitted. If the + * current file offset is at or past the end of file (i.e. EOD), no bytes + * are read, and the data() signal returns any empty QByteArray. + * + * On error the data() signal is not emitted. To catch errors please connect + * to the result() signal. + * + * @param size the requested amount of data to read * - * The slave emits the data through data(). - * @param size the requested amount of data */ void read(KIO::filesize_t size); /** - * Write block + * This function attempts to write all the bytes in \p data to the URL + * passed to KIO::open() and returns the bytes written received via the + * written() signal. + * + * The write operation commences at the current file + * offset, and the file offset is incremented by the number of bytes read, + * but this change in the offset does not result in the position() being + * emitted. + * + * On error the written() signal is not emitted. To catch errors please + * connect to the result() signal. * * @param data the data to write */ void write(const QByteArray &data); /** - * Close - * * Closes the file-slave + * + * The slave emits close() and result(). */ void close(); /** * Seek * - * The slave emits position() + * The slave emits position() on successful seek to the specified \p offset. + * + * On error the position() signal is not emitted. To catch errors please + * connect to the result() signal. + * * @param offset the position from start to go to */ void seek(KIO::filesize_t offset); @@ -83,9 +107,14 @@ Q_SIGNALS: /** - * Data from the slave has arrived. + * Data from the slave has arrived. emitted after read(). + * + * Unless a read() request was sent for 0 bytes, End of data (EOD) has been + * reached if data.size() == 0 + * * @param job the job that emitted this signal * @param data data received from the slave. + * */ void data(KIO::Job *job, const QByteArray &data); @@ -112,7 +141,7 @@ void open(KIO::Job *job); /** - * Bytes written to the file. + * \p written bytes were written to the file. Emitted after write(); * @param job the job that emitted this signal * @param written bytes written. */ @@ -125,7 +154,7 @@ void close(KIO::Job *job); /** - * The file has reached this position. Emitted after seek. + * The file has reached this position. Emitted after seek(). * @param job the job that emitted this signal * @param offset the new position */ diff --git a/src/core/filejob.cpp b/src/core/filejob.cpp --- a/src/core/filejob.cpp +++ b/src/core/filejob.cpp @@ -180,10 +180,11 @@ { Q_Q(FileJob); //qDebug() << this << m_url; + m_open = false; emit q->close(q); // Return slave to the scheduler slaveDone(); -// Scheduler::doJob(this); + // Scheduler::doJob(this); q->emitResult(); } @@ -202,6 +203,9 @@ q->connect(slave, SIGNAL(open()), SLOT(slotOpen())); + q->connect(slave, SIGNAL(finished()), + SLOT(slotFinished())); + q->connect(slave, SIGNAL(position(KIO::filesize_t)), SLOT(slotPosition(KIO::filesize_t))); diff --git a/src/core/slavebase.h b/src/core/slavebase.h --- a/src/core/slavebase.h +++ b/src/core/slavebase.h @@ -97,7 +97,7 @@ /** * open succeeds - * @see open + * @see open() */ void opened(); @@ -418,9 +418,28 @@ */ virtual void open(const QUrl &url, QIODevice::OpenMode mode); + /** + * read. + * @param size the requested amount of data to read + * @see KIO::FileJob::read() + */ virtual void read(KIO::filesize_t size); + /** + * write. + * @param data the data to write + * @see KIO::FileJob::write() + */ virtual void write(const QByteArray &data); + /** + * seek. + * @param offset the requested amount of data to read + * @see KIO::FileJob::read() + */ virtual void seek(KIO::filesize_t offset); + /** + * close. + * @see KIO::FileJob::close() + */ virtual void close(); /** diff --git a/src/core/slavebase.cpp b/src/core/slavebase.cpp --- a/src/core/slavebase.cpp +++ b/src/core/slavebase.cpp @@ -456,6 +456,12 @@ d->inOpenLoop = true; } +void SlaveBase::closed() +{ + send(MSG_CLOSED); + d->inOpenLoop = false; +} + void SlaveBase::error(int _errid, const QString &_text) { if (d->m_state == d->ErrorCalled) { diff --git a/src/core/slaveinterface.h b/src/core/slaveinterface.h --- a/src/core/slaveinterface.h +++ b/src/core/slaveinterface.h @@ -146,6 +146,7 @@ void open(); void written(KIO::filesize_t); + void close(); void privilegeOperationRequested(); diff --git a/src/core/slaveinterface.cpp b/src/core/slaveinterface.cpp --- a/src/core/slaveinterface.cpp +++ b/src/core/slaveinterface.cpp @@ -319,6 +319,9 @@ case MSG_PRIVILEGE_EXEC: emit privilegeOperationRequested(); break; + case MSG_CLOSED: + emit close(); + break; default: qCWarning(KIO_CORE) << "Slave sends unknown command (" << _cmd << "), dropping slave"; return false; diff --git a/src/ioslaves/file/file.h b/src/ioslaves/file/file.h --- a/src/ioslaves/file/file.h +++ b/src/ioslaves/file/file.h @@ -113,6 +113,9 @@ void redirect(const QUrl &url); + // Close without calling finish(). Use this to close after error. + void closeWithoutFinish(); + private: mutable QHash mUsercache; mutable QHash mGroupcache; diff --git a/src/ioslaves/file/file.cpp b/src/ioslaves/file/file.cpp --- a/src/ioslaves/file/file.cpp +++ b/src/ioslaves/file/file.cpp @@ -515,43 +515,44 @@ // qDebug() << "File::open -- read"; Q_ASSERT(mFile && mFile->isOpen()); - while (true) { - QByteArray res = mFile->read(bytes); + QVarLengthArray buffer(bytes); - if (!res.isEmpty()) { - data(res); - bytes -= res.size(); - } else { - // empty array designates eof - data(QByteArray()); - if (!mFile->atEnd()) { - error(KIO::ERR_CANNOT_READ, mFile->fileName()); - close(); - } - break; - } - if (bytes <= 0) { - break; - } + qint64 bytesRead = mFile->read(buffer.data(), bytes); + + if (bytesRead == -1) { + qCWarning(KIO_FILE) << "Couldn't read. Error:" << mFile->errorString(); + error(KIO::ERR_CANNOT_READ, mFile->fileName()); + closeWithoutFinish(); + } else { + const QByteArray fileData = QByteArray::fromRawData(buffer.data(), bytesRead); + data(fileData); } } void FileProtocol::write(const QByteArray &data) { // qDebug() << "File::open -- write"; Q_ASSERT(mFile && mFile->isWritable()); - if (mFile->write(data) != data.size()) { + qint64 bytesWritten = mFile->write(data); + + if (bytesWritten == -1) { if (mFile->error() == QFileDevice::ResourceError) { // disk full error(KIO::ERR_DISK_FULL, mFile->fileName()); - close(); + closeWithoutFinish(); } else { qCWarning(KIO_FILE) << "Couldn't write. Error:" << mFile->errorString(); error(KIO::ERR_CANNOT_WRITE, mFile->fileName()); - close(); + closeWithoutFinish(); } } else { - written(data.size()); + // Make sure data gets to disk. + if (mFile->flush()) + written(bytesWritten); + else { + error(KIO::ERR_CANNOT_WRITE, mFile->fileName()); + closeWithoutFinish(); + } } } @@ -564,18 +565,22 @@ position(offset); } else { error(KIO::ERR_CANNOT_SEEK, mFile->fileName()); - close(); + closeWithoutFinish(); } } -void FileProtocol::close() +void FileProtocol::closeWithoutFinish() { - // qDebug() << "File::open -- close "; Q_ASSERT(mFile); delete mFile; mFile = nullptr; +} +void FileProtocol::close() +{ + // qDebug() << "File::open -- close "; + closeWithoutFinish(); finished(); }