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
13QT_BEGIN_NAMESPACE
14
15#ifndef QFILE_WRITEBUFFER_SIZE
16#define QFILE_WRITEBUFFER_SIZE 16384
17#endif
18
19QFileDevicePrivate::QFileDevicePrivate()
20 : cachedSize(0),
21 error(QFile::NoError), lastWasWrite(false)
22{
23 writeBufferChunkSize = QFILE_WRITEBUFFER_SIZE;
24}
25
26QFileDevicePrivate::~QFileDevicePrivate() = default;
27
28QAbstractFileEngine *QFileDevicePrivate::engine() const
29{
30 if (!fileEngine)
31 fileEngine = std::make_unique<QFSFileEngine>();
32 return fileEngine.get();
33}
34
35void QFileDevicePrivate::setError(QFileDevice::FileError err)
36{
37 error = err;
38 errorString.clear();
39}
40
41void QFileDevicePrivate::setError(QFileDevice::FileError err, const QString &errStr)
42{
43 error = err;
44 errorString = errStr;
45}
46
47void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum)
48{
49 error = err;
50 errorString = qt_error_string(errorCode: errNum);
51}
52
53/*!
54 \enum QFileDevice::FileError
55
56 This enum describes the errors that may be returned by the error()
57 function.
58
59 \value NoError No error occurred.
60 \value ReadError An error occurred when reading from the file.
61 \value WriteError An error occurred when writing to the file.
62 \value FatalError A fatal error occurred.
63 \value ResourceError Out of resources (e.g., too many open files, out of memory, etc.)
64 \value OpenError The file could not be opened.
65 \value AbortError The operation was aborted.
66 \value TimeOutError A timeout occurred.
67 \value UnspecifiedError An unspecified error occurred.
68 \value RemoveError The file could not be removed.
69 \value RenameError The file could not be renamed.
70 \value PositionError The position in the file could not be changed.
71 \value ResizeError The file could not be resized.
72 \value PermissionsError The file could not be accessed.
73 \value CopyError The file could not be copied.
74*/
75
76/*!
77 \enum QFileDevice::Permission
78
79 This enum is used by the permission() function to report the
80 permissions and ownership of a file. The values may be OR-ed
81 together to test multiple permissions and ownership values.
82
83 \value ReadOwner The file is readable by the owner of the file.
84 \value WriteOwner The file is writable by the owner of the file.
85 \value ExeOwner The file is executable by the owner of the file.
86 \value ReadUser The file is readable by the user.
87 \value WriteUser The file is writable by the user.
88 \value ExeUser The file is executable by the user.
89 \value ReadGroup The file is readable by the group.
90 \value WriteGroup The file is writable by the group.
91 \value ExeGroup The file is executable by the group.
92 \value ReadOther The file is readable by others.
93 \value WriteOther The file is writable by others.
94 \value ExeOther The file is executable by others.
95
96 \warning Because of differences in the platforms supported by Qt,
97 the semantics of ReadUser, WriteUser and ExeUser are
98 platform-dependent: On Unix, the rights of the owner of the file
99 are returned and on Windows the rights of the current user are
100 returned. This behavior might change in a future Qt version.
101
102 \note On NTFS file systems, ownership and permissions checking is
103 disabled by default for performance reasons. To enable it,
104 include the following line:
105
106 \snippet ntfsp.cpp 0
107
108 Permission checking is then turned on and off by incrementing and
109 decrementing \c qt_ntfs_permission_lookup by 1.
110
111 \snippet ntfsp.cpp 1
112
113 \note Since this is a non-atomic global variable, it is only safe
114 to increment or decrement \c qt_ntfs_permission_lookup before any
115 threads other than the main thread have started or after every thread
116 other than the main thread has ended.
117
118 \note From Qt 6.6 the variable \c qt_ntfs_permission_lookup is
119 deprecated. Please use the following alternatives.
120
121 The safe and easy way to manage permission checks is to use the RAII class
122 \c QNtfsPermissionCheckGuard.
123
124 \snippet ntfsp.cpp raii
125
126 If you need more fine-grained control, it is possible to manage the permission
127 with the following functions instead:
128
129 \snippet ntfsp.cpp free-funcs
130
131*/
132
133//************* QFileDevice
134
135/*!
136 \class QFileDevice
137 \inmodule QtCore
138 \since 5.0
139
140 \brief The QFileDevice class provides an interface for reading from and writing to open files.
141
142 \ingroup io
143
144 \reentrant
145
146 QFileDevice is the base class for I/O devices that can read and write text and binary files
147 and \l{The Qt Resource System}{resources}. QFile offers the main functionality,
148 QFileDevice serves as a base class for sharing functionality with other file devices such
149 as QSaveFile, by providing all the operations that can be done on files that have
150 been opened by QFile or QSaveFile.
151
152 \sa QFile, QSaveFile
153*/
154
155/*!
156 \enum QFileDevice::FileHandleFlag
157
158 This enum is used when opening a file to specify additional
159 options which only apply to files and not to a generic
160 QIODevice.
161
162 \value AutoCloseHandle The file handle passed into open() should be
163 closed by close(), the default behavior is that close just flushes
164 the file and the application is responsible for closing the file handle.
165 When opening a file by name, this flag is ignored as Qt always owns the
166 file handle and must close it.
167 \value DontCloseHandle If not explicitly closed, the underlying file
168 handle is left open when the QFile object is destroyed.
169 */
170
171/*!
172 \macro QT_USE_NODISCARD_FILE_OPEN
173 \macro QT_NO_USE_NODISCARD_FILE_OPEN
174 \relates QFileDevice
175 \since 6.8
176
177 File-related I/O classes (such as QFile, QSaveFile, QTemporaryFile)
178 have an \c{open()} method to open the file they act upon. It is
179 important to check the return value of the call to \c{open()}
180 before proceeding with reading or writing data into the file.
181
182 For this reason, starting with Qt 6.8, some overloads of \c{open()}
183 have been marked with the \c{[[nodiscard]]} attribute. Since this
184 change may raise warnings in existing codebases, user code can
185 opt-in or opt-out from having the attribute applied by defining
186 certain macros:
187
188 \list
189 \li If the \c{QT_USE_NODISCARD_FILE_OPEN} macro is defined,
190 overloads of \c{open()} are marked as \c{[[nodiscard]]}.
191 \li If the \c{QT_NO_USE_NODISCARD_FILE_OPEN} is defined, the
192 overloads of \c{open()} are \e{not} marked as \c{[[nodiscard]]}.
193 \li If neither macro is defined, then the default up to and
194 including Qt 6.9 is not to have the attribute. Starting from Qt 6.10,
195 the attribute is automatically applied.
196 \li If both macros are defined, the program is ill-formed.
197 \endlist
198*/
199
200#ifdef QT_NO_QOBJECT
201QFileDevice::QFileDevice()
202 : QIODevice(*new QFileDevicePrivate)
203{
204}
205QFileDevice::QFileDevice(QFileDevicePrivate &dd)
206 : QIODevice(dd)
207{
208}
209#else
210/*!
211 \internal
212*/
213QFileDevice::QFileDevice()
214 : QIODevice(*new QFileDevicePrivate, nullptr)
215{
216}
217/*!
218 \internal
219*/
220QFileDevice::QFileDevice(QObject *parent)
221 : QIODevice(*new QFileDevicePrivate, parent)
222{
223}
224/*!
225 \internal
226*/
227QFileDevice::QFileDevice(QFileDevicePrivate &dd, QObject *parent)
228 : QIODevice(dd, parent)
229{
230}
231#endif
232
233/*!
234 Destroys the file device, closing it if necessary.
235*/
236QFileDevice::~QFileDevice()
237{
238 close();
239}
240
241/*!
242 Returns \c true if the file can only be manipulated sequentially;
243 otherwise returns \c false.
244
245 Most files support random-access, but some special files may not.
246
247 \sa QIODevice::isSequential()
248*/
249bool QFileDevice::isSequential() const
250{
251 Q_D(const QFileDevice);
252 return d->fileEngine && d->fileEngine->isSequential();
253}
254
255/*!
256 Returns the file handle of the file.
257
258 This is a small positive integer, suitable for use with C library
259 functions such as \c fdopen() and \c fcntl(). On systems that use file
260 descriptors for sockets (i.e. Unix systems, but not Windows) the handle
261 can be used with QSocketNotifier as well.
262
263 If the file is not open, or there is an error, handle() returns -1.
264
265 \sa QSocketNotifier
266*/
267int QFileDevice::handle() const
268{
269 Q_D(const QFileDevice);
270 if (!isOpen() || !d->fileEngine)
271 return -1;
272
273 return d->fileEngine->handle();
274}
275
276/*!
277 Returns the name of the file.
278 The default implementation in QFileDevice returns a null string.
279*/
280QString QFileDevice::fileName() const
281{
282 return QString();
283}
284
285/*!
286 Flushes any buffered data to the file. Returns \c true if successful;
287 otherwise returns \c false.
288*/
289bool QFileDevice::flush()
290{
291 Q_D(QFileDevice);
292 if (!d->fileEngine) {
293 qWarning(msg: "QFileDevice::flush: No file engine. Is IODevice open?");
294 return false;
295 }
296
297 if (!d->writeBuffer.isEmpty()) {
298 qint64 size = d->writeBuffer.nextDataBlockSize();
299 qint64 written = d->fileEngine->write(data: d->writeBuffer.readPointer(), len: size);
300 if (written > 0)
301 d->writeBuffer.free(bytes: written);
302 if (written != size) {
303 QFileDevice::FileError err = d->fileEngine->error();
304 if (err == QFileDevice::UnspecifiedError)
305 err = QFileDevice::WriteError;
306 d->setError(err, errStr: d->fileEngine->errorString());
307 return false;
308 }
309 }
310
311 if (!d->fileEngine->flush()) {
312 QFileDevice::FileError err = d->fileEngine->error();
313 if (err == QFileDevice::UnspecifiedError)
314 err = QFileDevice::WriteError;
315 d->setError(err, errStr: d->fileEngine->errorString());
316 return false;
317 }
318 return true;
319}
320
321/*!
322 Calls QFileDevice::flush() and closes the file. Errors from flush are ignored.
323
324 \sa QIODevice::close()
325*/
326void QFileDevice::close()
327{
328 Q_D(QFileDevice);
329 if (!isOpen())
330 return;
331 bool flushed = flush();
332 QIODevice::close();
333
334 // reset write buffer
335 d->lastWasWrite = false;
336 d->writeBuffer.clear();
337
338 // reset cached size
339 d->cachedSize = 0;
340
341 // keep earlier error from flush
342 if (d->fileEngine->close() && flushed)
343 unsetError();
344 else if (flushed)
345 d->setError(err: d->fileEngine->error(), errStr: d->fileEngine->errorString());
346}
347
348/*!
349 \reimp
350*/
351qint64 QFileDevice::pos() const
352{
353 return QIODevice::pos();
354}
355
356/*!
357 Returns \c true if the end of the file has been reached; otherwise returns
358 false.
359
360 For regular empty files on Unix (e.g. those in \c /proc), this function
361 returns \c true, since the file system reports that the size of such a file is
362 0. Therefore, you should not depend on atEnd() when reading data from such a
363 file, but rather call read() until no more data can be read.
364*/
365bool QFileDevice::atEnd() const
366{
367 Q_D(const QFileDevice);
368
369 // If there's buffered data left, we're not at the end.
370 if (!d->isBufferEmpty())
371 return false;
372
373 if (!isOpen())
374 return true;
375
376 if (!d->ensureFlushed())
377 return false;
378
379 // If the file engine knows best, say what it says.
380 if (d->fileEngine->supportsExtension(extension: QAbstractFileEngine::AtEndExtension)) {
381 // Check if the file engine supports AtEndExtension, and if it does,
382 // check if the file engine claims to be at the end.
383 return d->fileEngine->atEnd();
384 }
385
386 // if it looks like we are at the end, or if size is not cached,
387 // fall through to bytesAvailable() to make sure.
388 if (pos() < d->cachedSize)
389 return false;
390
391 // Fall back to checking how much is available (will stat files).
392 return bytesAvailable() == 0;
393}
394
395/*!
396 \fn bool QFileDevice::seek(qint64 pos)
397
398 For random-access devices, this function sets the current position
399 to \a pos, returning true on success, or false if an error occurred.
400 For sequential devices, the default behavior is to do nothing and
401 return false.
402
403 Seeking beyond the end of a file:
404 If the position is beyond the end of a file, then seek() will not
405 immediately extend the file. If a write is performed at this position,
406 then the file will be extended. The content of the file between the
407 previous end of file and the newly written data is UNDEFINED and
408 varies between platforms and file systems.
409*/
410bool QFileDevice::seek(qint64 off)
411{
412 Q_D(QFileDevice);
413 if (!isOpen()) {
414 qWarning(msg: "QFileDevice::seek: IODevice is not open");
415 return false;
416 }
417
418 if (!d->ensureFlushed())
419 return false;
420
421 if (!d->fileEngine->seek(pos: off) || !QIODevice::seek(pos: off)) {
422 QFileDevice::FileError err = d->fileEngine->error();
423 if (err == QFileDevice::UnspecifiedError)
424 err = QFileDevice::PositionError;
425 d->setError(err, errStr: d->fileEngine->errorString());
426 return false;
427 }
428 unsetError();
429 return true;
430}
431
432/*!
433 \reimp
434*/
435qint64 QFileDevice::readLineData(char *data, qint64 maxlen)
436{
437 Q_D(QFileDevice);
438 if (!d->ensureFlushed())
439 return -1;
440
441 qint64 read;
442 if (d->fileEngine->supportsExtension(extension: QAbstractFileEngine::FastReadLineExtension)) {
443 read = d->fileEngine->readLine(data, maxlen);
444 } else {
445 // Fall back to QIODevice's readLine implementation if the engine
446 // cannot do it faster.
447 read = QIODevice::readLineData(data, maxlen);
448 }
449
450 if (read < maxlen) {
451 // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
452 d->cachedSize = 0;
453 }
454
455 return read;
456}
457
458/*!
459 \reimp
460*/
461qint64 QFileDevice::readData(char *data, qint64 len)
462{
463 Q_D(QFileDevice);
464 if (!len)
465 return 0;
466 unsetError();
467 if (!d->ensureFlushed())
468 return -1;
469
470 const qint64 read = d->fileEngine->read(data, maxlen: len);
471 if (read < 0) {
472 QFileDevice::FileError err = d->fileEngine->error();
473 if (err == QFileDevice::UnspecifiedError)
474 err = QFileDevice::ReadError;
475 d->setError(err, errStr: d->fileEngine->errorString());
476 }
477
478 if (read < len) {
479 // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
480 d->cachedSize = 0;
481 }
482
483 return read;
484}
485
486/*!
487 \internal
488*/
489bool QFileDevicePrivate::putCharHelper(char c)
490{
491#ifdef QT_NO_QOBJECT
492 return QIODevicePrivate::putCharHelper(c);
493#else
494
495 // Cutoff for code that doesn't only touch the buffer.
496 qint64 writeBufferSize = writeBuffer.size();
497 if ((openMode & QIODevice::Unbuffered) || writeBufferSize + 1 >= writeBufferChunkSize
498#ifdef Q_OS_WIN
499 || ((openMode & QIODevice::Text) && c == '\n'
500 && writeBufferSize + 2 >= writeBufferChunkSize)
501#endif
502 ) {
503 return QIODevicePrivate::putCharHelper(c);
504 }
505
506 if (!(openMode & QIODevice::WriteOnly)) {
507 if (openMode == QIODevice::NotOpen)
508 qWarning(msg: "QIODevice::putChar: Closed device");
509 else
510 qWarning(msg: "QIODevice::putChar: ReadOnly device");
511 return false;
512 }
513
514 // Make sure the device is positioned correctly.
515 const bool sequential = isSequential();
516 if (pos != devicePos && !sequential && !q_func()->seek(off: pos))
517 return false;
518
519 lastWasWrite = true;
520
521 int len = 1;
522#ifdef Q_OS_WIN
523 if ((openMode & QIODevice::Text) && c == '\n') {
524 ++len;
525 *writeBuffer.reserve(1) = '\r';
526 }
527#endif
528
529 // Write to buffer.
530 *writeBuffer.reserve(bytes: 1) = c;
531
532 if (!sequential) {
533 pos += len;
534 devicePos += len;
535 if (!buffer.isEmpty())
536 buffer.skip(length: len);
537 }
538
539 return true;
540#endif
541}
542
543/*!
544 \reimp
545*/
546qint64 QFileDevice::writeData(const char *data, qint64 len)
547{
548 Q_D(QFileDevice);
549 unsetError();
550 d->lastWasWrite = true;
551 bool buffered = !(d->openMode & Unbuffered);
552
553 // Flush buffered data if this read will overflow.
554 if (buffered && (d->writeBuffer.size() + len) > d->writeBufferChunkSize) {
555 if (!flush())
556 return -1;
557 }
558
559 // Write directly to the engine if the block size is larger than
560 // the write buffer size.
561 if (!buffered || len > d->writeBufferChunkSize) {
562 const qint64 ret = d->fileEngine->write(data, len);
563 if (ret < 0) {
564 QFileDevice::FileError err = d->fileEngine->error();
565 if (err == QFileDevice::UnspecifiedError)
566 err = QFileDevice::WriteError;
567 d->setError(err, errStr: d->fileEngine->errorString());
568 }
569 return ret;
570 }
571
572 // Write to the buffer.
573 d->writeBuffer.append(data, size: len);
574 return len;
575}
576
577/*!
578 Returns the file error status.
579
580 The I/O device status returns an error code. For example, if open()
581 returns \c false, or a read/write operation returns -1, this function can
582 be called to find out the reason why the operation failed.
583
584 \sa unsetError()
585*/
586QFileDevice::FileError QFileDevice::error() const
587{
588 Q_D(const QFileDevice);
589 return d->error;
590}
591
592/*!
593 Sets the file's error to QFileDevice::NoError.
594
595 \sa error()
596*/
597void QFileDevice::unsetError()
598{
599 Q_D(QFileDevice);
600 d->setError(QFileDevice::NoError);
601}
602
603/*!
604 Returns the size of the file.
605
606 For regular empty files on Unix (e.g. those in \c /proc), this function
607 returns 0; the contents of such a file are generated on demand in response
608 to you calling read().
609*/
610qint64 QFileDevice::size() const
611{
612 Q_D(const QFileDevice);
613 if (!d->ensureFlushed())
614 return 0;
615 d->cachedSize = d->engine()->size();
616 return d->cachedSize;
617}
618
619/*!
620 Sets the file size (in bytes) \a sz. Returns \c true if the
621 resize succeeds; false otherwise. If \a sz is larger than the file
622 currently is, the new bytes will be set to 0; if \a sz is smaller, the
623 file is simply truncated.
624
625 \warning This function can fail if the file doesn't exist.
626
627 \sa size()
628*/
629bool QFileDevice::resize(qint64 sz)
630{
631 Q_D(QFileDevice);
632 if (!d->ensureFlushed())
633 return false;
634 d->engine();
635 if (isOpen() && d->fileEngine->pos() > sz)
636 seek(off: sz);
637 if (d->fileEngine->setSize(sz)) {
638 unsetError();
639 d->cachedSize = sz;
640 return true;
641 }
642 d->cachedSize = 0;
643 d->setError(err: QFile::ResizeError, errStr: d->fileEngine->errorString());
644 return false;
645}
646
647/*!
648 Returns the complete OR-ed together combination of
649 QFile::Permission for the file.
650
651 \sa setPermissions()
652*/
653QFile::Permissions QFileDevice::permissions() const
654{
655 Q_D(const QFileDevice);
656 QAbstractFileEngine::FileFlags perms = d->engine()->fileFlags(type: QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask;
657 return QFile::Permissions::fromInt(i: perms.toInt()); //ewww
658}
659
660/*!
661 Sets the permissions for the file to the \a permissions specified.
662 Returns \c true if successful, or \c false if the permissions cannot be
663 modified.
664
665 \warning This function does not manipulate ACLs, which may limit its
666 effectiveness.
667
668 \sa permissions()
669*/
670bool QFileDevice::setPermissions(Permissions permissions)
671{
672 Q_D(QFileDevice);
673 if (d->engine()->setPermissions(permissions.toInt())) {
674 unsetError();
675 return true;
676 }
677 d->setError(err: QFile::PermissionsError, errStr: d->fileEngine->errorString());
678 return false;
679}
680
681/*!
682 \enum QFileDevice::MemoryMapFlag
683 \since 4.4
684
685 This enum describes special options that may be used by the map()
686 function.
687
688 \value NoOptions No options.
689 \value MapPrivateOption The mapped memory will be private, so any
690 modifications will not be visible to other processes and will not
691 be written to disk. Any such modifications will be lost when the
692 memory is unmapped. It is unspecified whether modifications made
693 to the file made after the mapping is created will be visible through
694 the mapped memory. This enum value was introduced in Qt 5.4.
695*/
696
697/*!
698 Maps \a size bytes of the file into memory starting at \a offset. A file
699 should be open for a map to succeed but the file does not need to stay
700 open after the memory has been mapped. When the QFile is destroyed
701 or a new file is opened with this object, any maps that have not been
702 unmapped will automatically be unmapped.
703
704 The mapping will have the same open mode as the file (read and/or write),
705 except when using MapPrivateOption, in which case it is always possible
706 to write to the mapped memory.
707
708 Any mapping options can be passed through \a flags.
709
710 Returns a pointer to the memory or \nullptr if there is an error.
711
712 \sa unmap()
713 */
714uchar *QFileDevice::map(qint64 offset, qint64 size, MemoryMapFlags flags)
715{
716 Q_D(QFileDevice);
717 if (d->engine()
718 && d->fileEngine->supportsExtension(extension: QAbstractFileEngine::MapExtension)) {
719 unsetError();
720 uchar *address = d->fileEngine->map(offset, size, flags);
721 if (address == nullptr)
722 d->setError(err: d->fileEngine->error(), errStr: d->fileEngine->errorString());
723 return address;
724 }
725 return nullptr;
726}
727
728/*!
729 Unmaps the memory \a address.
730
731 Returns \c true if the unmap succeeds; false otherwise.
732
733 \sa map()
734 */
735bool QFileDevice::unmap(uchar *address)
736{
737 Q_D(QFileDevice);
738 if (d->engine()
739 && d->fileEngine->supportsExtension(extension: QAbstractFileEngine::UnMapExtension)) {
740 unsetError();
741 bool success = d->fileEngine->unmap(ptr: address);
742 if (!success)
743 d->setError(err: d->fileEngine->error(), errStr: d->fileEngine->errorString());
744 return success;
745 }
746 d->setError(err: PermissionsError, errStr: tr(s: "No file engine available or engine does not support UnMapExtension"));
747 return false;
748}
749
750/*!
751 \enum QFileDevice::FileTime
752 \since 5.10
753
754 This enum is used by the fileTime() and setFileTime() functions.
755
756 \value FileAccessTime When the file was most recently accessed
757 (e.g. read or written to).
758 \value FileBirthTime When the file was created (may not be not
759 supported on UNIX).
760 \value FileMetadataChangeTime When the file's metadata was last changed.
761 \value FileModificationTime When the file was most recently modified.
762
763 \sa setFileTime(), fileTime(), QFileInfo::fileTime()
764*/
765
766/*!
767 \since 5.10
768 Returns the file time specified by \a time.
769 If the time cannot be determined return QDateTime() (an invalid
770 date time).
771
772 \sa setFileTime(), FileTime, QDateTime::isValid()
773*/
774QDateTime QFileDevice::fileTime(QFileDevice::FileTime time) const
775{
776 Q_D(const QFileDevice);
777
778 if (d->engine())
779 return d->engine()->fileTime(time);
780
781 return QDateTime();
782}
783
784/*!
785 \since 5.10
786 Sets the file time specified by \a fileTime to \a newDate, returning true
787 if successful; otherwise returns false.
788
789 \note The file must be open to use this function.
790
791 \sa fileTime(), FileTime
792*/
793bool QFileDevice::setFileTime(const QDateTime &newDate, QFileDevice::FileTime fileTime)
794{
795 Q_D(QFileDevice);
796
797 if (!d->engine()) {
798 d->setError(err: QFileDevice::UnspecifiedError, errStr: tr(s: "No file engine available"));
799 return false;
800 }
801
802 if (!d->fileEngine->setFileTime(newDate, time: fileTime)) {
803 d->setError(err: d->fileEngine->error(), errStr: d->fileEngine->errorString());
804 return false;
805 }
806
807 unsetError();
808 return true;
809}
810
811QT_END_NAMESPACE
812
813#ifndef QT_NO_QOBJECT
814#include "moc_qfiledevice.cpp"
815#endif
816

source code of qtbase/src/corelib/io/qfiledevice.cpp