Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qfiledevice.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qplatformdefs.h"
5#include "qfiledevice.h"
6#include "qfiledevice_p.h"
7#include "qfsfileengine_p.h"
8
9#ifdef QT_NO_QOBJECT
10#define tr(X) QString::fromLatin1(X)
11#endif
12
14
15#ifndef QFILE_WRITEBUFFER_SIZE
16#define QFILE_WRITEBUFFER_SIZE 16384
17#endif
18
20 : cachedSize(0),
21 error(QFile::NoError), lastWasWrite(false)
22{
24}
25
27
29{
30 if (!fileEngine)
31 fileEngine = std::make_unique<QFSFileEngine>();
32 return fileEngine.get();
33}
34
36{
37 error = err;
39}
40
42{
43 error = err;
44 errorString = errStr;
45}
46
48{
49 error = err;
51}
52
133//************* QFileDevice
134
171#ifdef QT_NO_QOBJECT
174{
175}
177 : QIODevice(dd)
178{
179}
180#else
186{
187}
193{
194}
199 : QIODevice(dd, parent)
200{
201}
202#endif
203
208{
209 close();
210}
211
221{
222 Q_D(const QFileDevice);
223 return d->fileEngine && d->fileEngine->isSequential();
224}
225
239{
240 Q_D(const QFileDevice);
241 if (!isOpen() || !d->fileEngine)
242 return -1;
243
244 return d->fileEngine->handle();
245}
246
252{
253 return QString();
254}
255
261{
262 Q_D(QFileDevice);
263 if (!d->fileEngine) {
264 qWarning("QFileDevice::flush: No file engine. Is IODevice open?");
265 return false;
266 }
267
268 if (!d->writeBuffer.isEmpty()) {
269 qint64 size = d->writeBuffer.nextDataBlockSize();
270 qint64 written = d->fileEngine->write(d->writeBuffer.readPointer(), size);
271 if (written > 0)
272 d->writeBuffer.free(written);
273 if (written != size) {
274 QFileDevice::FileError err = d->fileEngine->error();
277 d->setError(err, d->fileEngine->errorString());
278 return false;
279 }
280 }
281
282 if (!d->fileEngine->flush()) {
283 QFileDevice::FileError err = d->fileEngine->error();
286 d->setError(err, d->fileEngine->errorString());
287 return false;
288 }
289 return true;
290}
291
298{
299 Q_D(QFileDevice);
300 if (!isOpen())
301 return;
302 bool flushed = flush();
304
305 // reset write buffer
306 d->lastWasWrite = false;
307 d->writeBuffer.clear();
308
309 // reset cached size
310 d->cachedSize = 0;
311
312 // keep earlier error from flush
313 if (d->fileEngine->close() && flushed)
314 unsetError();
315 else if (flushed)
316 d->setError(d->fileEngine->error(), d->fileEngine->errorString());
317}
318
323{
324 return QIODevice::pos();
325}
326
337{
338 Q_D(const QFileDevice);
339
340 // If there's buffered data left, we're not at the end.
341 if (!d->isBufferEmpty())
342 return false;
343
344 if (!isOpen())
345 return true;
346
347 if (!d->ensureFlushed())
348 return false;
349
350 // If the file engine knows best, say what it says.
351 if (d->fileEngine->supportsExtension(QAbstractFileEngine::AtEndExtension)) {
352 // Check if the file engine supports AtEndExtension, and if it does,
353 // check if the file engine claims to be at the end.
354 return d->fileEngine->atEnd();
355 }
356
357 // if it looks like we are at the end, or if size is not cached,
358 // fall through to bytesAvailable() to make sure.
359 if (pos() < d->cachedSize)
360 return false;
361
362 // Fall back to checking how much is available (will stat files).
363 return bytesAvailable() == 0;
364}
365
382{
383 Q_D(QFileDevice);
384 if (!isOpen()) {
385 qWarning("QFileDevice::seek: IODevice is not open");
386 return false;
387 }
388
389 if (!d->ensureFlushed())
390 return false;
391
392 if (!d->fileEngine->seek(off) || !QIODevice::seek(off)) {
393 QFileDevice::FileError err = d->fileEngine->error();
396 d->setError(err, d->fileEngine->errorString());
397 return false;
398 }
399 unsetError();
400 return true;
401}
402
407{
408 Q_D(QFileDevice);
409 if (!d->ensureFlushed())
410 return -1;
411
412 qint64 read;
413 if (d->fileEngine->supportsExtension(QAbstractFileEngine::FastReadLineExtension)) {
414 read = d->fileEngine->readLine(data, maxlen);
415 } else {
416 // Fall back to QIODevice's readLine implementation if the engine
417 // cannot do it faster.
419 }
420
421 if (read < maxlen) {
422 // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
423 d->cachedSize = 0;
424 }
425
426 return read;
427}
428
433{
434 Q_D(QFileDevice);
435 if (!len)
436 return 0;
437 unsetError();
438 if (!d->ensureFlushed())
439 return -1;
440
441 const qint64 read = d->fileEngine->read(data, len);
442 if (read < 0) {
443 QFileDevice::FileError err = d->fileEngine->error();
446 d->setError(err, d->fileEngine->errorString());
447 }
448
449 if (read < len) {
450 // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
451 d->cachedSize = 0;
452 }
453
454 return read;
455}
456
461{
462#ifdef QT_NO_QOBJECT
464#else
465
466 // Cutoff for code that doesn't only touch the buffer.
467 qint64 writeBufferSize = writeBuffer.size();
468 if ((openMode & QIODevice::Unbuffered) || writeBufferSize + 1 >= writeBufferChunkSize
469#ifdef Q_OS_WIN
470 || ((openMode & QIODevice::Text) && c == '\n'
471 && writeBufferSize + 2 >= writeBufferChunkSize)
472#endif
473 ) {
475 }
476
479 qWarning("QIODevice::putChar: Closed device");
480 else
481 qWarning("QIODevice::putChar: ReadOnly device");
482 return false;
483 }
484
485 // Make sure the device is positioned correctly.
486 const bool sequential = isSequential();
487 if (pos != devicePos && !sequential && !q_func()->seek(pos))
488 return false;
489
490 lastWasWrite = true;
491
492 int len = 1;
493#ifdef Q_OS_WIN
494 if ((openMode & QIODevice::Text) && c == '\n') {
495 ++len;
496 *writeBuffer.reserve(1) = '\r';
497 }
498#endif
499
500 // Write to buffer.
501 *writeBuffer.reserve(1) = c;
502
503 if (!sequential) {
504 pos += len;
505 devicePos += len;
506 if (!buffer.isEmpty())
507 buffer.skip(len);
508 }
509
510 return true;
511#endif
512}
513
518{
519 Q_D(QFileDevice);
520 unsetError();
521 d->lastWasWrite = true;
522 bool buffered = !(d->openMode & Unbuffered);
523
524 // Flush buffered data if this read will overflow.
525 if (buffered && (d->writeBuffer.size() + len) > d->writeBufferChunkSize) {
526 if (!flush())
527 return -1;
528 }
529
530 // Write directly to the engine if the block size is larger than
531 // the write buffer size.
532 if (!buffered || len > d->writeBufferChunkSize) {
533 const qint64 ret = d->fileEngine->write(data, len);
534 if (ret < 0) {
535 QFileDevice::FileError err = d->fileEngine->error();
538 d->setError(err, d->fileEngine->errorString());
539 }
540 return ret;
541 }
542
543 // Write to the buffer.
544 d->writeBuffer.append(data, len);
545 return len;
546}
547
558{
559 Q_D(const QFileDevice);
560 return d->error;
561}
562
569{
570 Q_D(QFileDevice);
571 d->setError(QFileDevice::NoError);
572}
573
582{
583 Q_D(const QFileDevice);
584 if (!d->ensureFlushed())
585 return 0;
586 d->cachedSize = d->engine()->size();
587 return d->cachedSize;
588}
589
601{
602 Q_D(QFileDevice);
603 if (!d->ensureFlushed())
604 return false;
605 d->engine();
606 if (isOpen() && d->fileEngine->pos() > sz)
607 seek(sz);
608 if (d->fileEngine->setSize(sz)) {
609 unsetError();
610 d->cachedSize = sz;
611 return true;
612 }
613 d->cachedSize = 0;
614 d->setError(QFile::ResizeError, d->fileEngine->errorString());
615 return false;
616}
617
624QFile::Permissions QFileDevice::permissions() const
625{
626 Q_D(const QFileDevice);
627 QAbstractFileEngine::FileFlags perms = d->engine()->fileFlags(QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask;
628 return QFile::Permissions::fromInt(perms.toInt()); //ewww
629}
630
641bool QFileDevice::setPermissions(Permissions permissions)
642{
643 Q_D(QFileDevice);
644 if (d->engine()->setPermissions(permissions.toInt())) {
645 unsetError();
646 return true;
647 }
648 d->setError(QFile::PermissionsError, d->fileEngine->errorString());
649 return false;
650}
651
686{
687 Q_D(QFileDevice);
688 if (d->engine()
689 && d->fileEngine->supportsExtension(QAbstractFileEngine::MapExtension)) {
690 unsetError();
691 uchar *address = d->fileEngine->map(offset, size, flags);
692 if (address == nullptr)
693 d->setError(d->fileEngine->error(), d->fileEngine->errorString());
694 return address;
695 }
696 return nullptr;
697}
698
707{
708 Q_D(QFileDevice);
709 if (d->engine()
710 && d->fileEngine->supportsExtension(QAbstractFileEngine::UnMapExtension)) {
711 unsetError();
712 bool success = d->fileEngine->unmap(address);
713 if (!success)
714 d->setError(d->fileEngine->error(), d->fileEngine->errorString());
715 return success;
716 }
717 d->setError(PermissionsError, tr("No file engine available or engine does not support UnMapExtension"));
718 return false;
719}
720
738{
744}
745
755{
756 Q_D(const QFileDevice);
757
758 if (d->engine())
759 return d->engine()->fileTime(FileDeviceTimeToAbstractFileEngineTime(time));
760
761 return QDateTime();
762}
763
774{
775 Q_D(QFileDevice);
776
777 if (!d->engine()) {
778 d->setError(QFileDevice::UnspecifiedError, tr("No file engine available"));
779 return false;
780 }
781
782 if (!d->fileEngine->setFileTime(newDate, FileDeviceTimeToAbstractFileEngineTime(fileTime))) {
783 d->setError(d->fileEngine->error(), d->fileEngine->errorString());
784 return false;
785 }
786
787 unsetError();
788 return true;
789}
790
792
793#ifndef QT_NO_QOBJECT
794#include "moc_qfiledevice.cpp"
795#endif
\inmodule QtCore \reentrant
FileTime
These are used by the fileTime() function.
\inmodule QtCore\reentrant
Definition qdatetime.h:257
bool putCharHelper(char c) override
std::unique_ptr< QAbstractFileEngine > fileEngine
virtual QAbstractFileEngine * engine() const
void setError(QFileDevice::FileError err)
QFileDevice::FileError error
\inmodule QtCore
Definition qfiledevice.h:16
qint64 readLineData(char *data, qint64 maxlen) override
\reimp
qint64 readData(char *data, qint64 maxlen) override
\reimp
bool flush()
Flushes any buffered data to the file.
~QFileDevice()
Destroys the file device, closing it if necessary.
QDateTime fileTime(QFileDevice::FileTime time) const
qint64 pos() const override
\reimp
bool seek(qint64 offset) override
For random-access devices, this function sets the current position to pos, returning true on success,...
qint64 size() const override
Returns the size of the file.
void unsetError()
Sets the file's error to QFileDevice::NoError.
virtual bool resize(qint64 sz)
Sets the file size (in bytes) sz.
qint64 writeData(const char *data, qint64 len) override
\reimp
@ FileMetadataChangeTime
Definition qfiledevice.h:44
@ FileModificationTime
Definition qfiledevice.h:45
uchar * map(qint64 offset, qint64 size, MemoryMapFlags flags=NoOptions)
Maps size bytes of the file into memory starting at offset.
int handle() const
Returns the file handle of the file.
bool setFileTime(const QDateTime &newDate, QFileDevice::FileTime fileTime)
bool atEnd() const override
Returns true if the end of the file has been reached; otherwise returns false.
FileError error() const
Returns the file error status.
bool isSequential() const override
Returns true if the file can only be manipulated sequentially; otherwise returns false.
virtual QString fileName() const
Returns the name of the file.
FileError
This enum describes the errors that may be returned by the error() function.
Definition qfiledevice.h:23
virtual bool setPermissions(Permissions permissionSpec)
Sets the permissions for the file to the permissions specified.
bool unmap(uchar *address)
Unmaps the memory address.
void close() override
Calls QFileDevice::flush() and closes the file.
virtual Permissions permissions() const
Returns the complete OR-ed together combination of QFile::Permission for the file.
\inmodule QtCore
Definition qfile.h:93
QIODevice::OpenMode openMode
bool isSequential() const
virtual bool putCharHelper(char c)
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
bool isOpen() const
Returns true if the device is open; otherwise returns false.
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
virtual qint64 readLineData(char *data, qint64 maxlen)
Reads up to maxSize characters into data and returns the number of characters read.
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
\inmodule QtCore
Definition qobject.h:90
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
Combined button and popup list for selecting options.
DBusConnection const char DBusError * error
#define QFILE_WRITEBUFFER_SIZE
static QAbstractFileEngine::FileTime FileDeviceTimeToAbstractFileEngineTime(QFileDevice::FileTime time)
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define qWarning
Definition qlogging.h:162
return ret
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint buffer
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
const GLubyte * c
GLenum GLsizei len
GLuint writeBuffer
GLuint GLuint64EXT address
@ NoError
Definition main.cpp:34
#define tr(X)
unsigned char uchar
Definition qtypes.h:27
long long qint64
Definition qtypes.h:55
QObject::connect nullptr
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent