Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qfsfileengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:data-parser
5
9#include "qdatetime.h"
10#include "qset.h"
11#include <QtCore/qdebug.h>
12
13#ifndef QT_NO_FSFILEENGINE
14
15#include <errno.h>
16#if defined(Q_OS_UNIX)
17#include "private/qcore_unix_p.h"
18#endif
19#include <stdio.h>
20#include <stdlib.h>
21#if defined(Q_OS_DARWIN)
22# include <private/qcore_mac_p.h>
23#endif
24
25QT_BEGIN_NAMESPACE
26
27using namespace Qt::StringLiterals;
28
29#ifdef Q_OS_WIN
30# ifndef S_ISREG
31# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
32# endif
33# ifndef S_ISCHR
34# define S_ISCHR(x) (((x) & S_IFMT) == S_IFCHR)
35# endif
36# ifndef S_ISFIFO
37# define S_ISFIFO(x) false
38# endif
39# ifndef S_ISSOCK
40# define S_ISSOCK(x) false
41# endif
42# ifndef INVALID_FILE_ATTRIBUTES
43# define INVALID_FILE_ATTRIBUTES (DWORD (-1))
44# endif
45#endif
46
47#ifdef Q_OS_WIN
48// on Windows, read() and write() use int and unsigned int
49typedef int SignedIOType;
50typedef unsigned int UnsignedIOType;
51#else
54static_assert(sizeof(SignedIOType) == sizeof(UnsignedIOType),
55 "Unsupported: read/write return a type with different size as the len parameter");
56#endif
57
58/*! \class QFSFileEngine
59 \inmodule QtCore
60 \brief The QFSFileEngine class implements Qt's default file engine.
61 \since 4.1
62 \internal
63
64 This class is part of the file engine framework in Qt. If you only want to
65 access files or directories, use QFile, QFileInfo or QDir instead.
66
67 QFSFileEngine is the default file engine for accessing regular files. It
68 is provided for convenience; by subclassing this class, you can alter its
69 behavior slightly, without having to write a complete QAbstractFileEngine
70 subclass. To install your custom file engine, you must also subclass
71 QAbstractFileEngineHandler and create an instance of your handler.
72
73 It can also be useful to create a QFSFileEngine object directly if you
74 need to use the local file system inside QAbstractFileEngine::create(), in
75 order to avoid recursion (as higher-level classes tend to call
76 QAbstractFileEngine::create()).
77*/
78
79//**************** QFSFileEnginePrivate
80QFSFileEnginePrivate::QFSFileEnginePrivate(QAbstractFileEngine *q)
81 : QAbstractFileEnginePrivate(q)
82{
83 init();
84}
85
86/*!
87 \internal
88*/
89void QFSFileEnginePrivate::init()
90{
91 is_sequential = 0;
92 tried_stat = 0;
93 need_lstat = 1;
94 is_link = 0;
95 openMode = QIODevice::NotOpen;
96 fd = -1;
97 fh = nullptr;
98 lastIOCommand = IOFlushCommand;
99 lastFlushFailed = false;
100 closeFileHandle = false;
101#ifdef Q_OS_WIN
102 fileAttrib = INVALID_FILE_ATTRIBUTES;
103 fileHandle = INVALID_HANDLE_VALUE;
104 mapHandle = NULL;
105 cachedFd = -1;
106#endif
107}
108
109/*!
110 Constructs a QFSFileEngine for the file name \a file.
111*/
112QFSFileEngine::QFSFileEngine(const QString &file)
113 : QAbstractFileEngine(*new QFSFileEnginePrivate(this))
114{
115 Q_D(QFSFileEngine);
116 d->fileEntry = QFileSystemEntry(file);
117}
118
119/*!
120 Constructs a QFSFileEngine.
121*/
122QFSFileEngine::QFSFileEngine() : QAbstractFileEngine(*new QFSFileEnginePrivate(this))
123{
124}
125
126/*!
127 \internal
128*/
129QFSFileEngine::QFSFileEngine(QFSFileEnginePrivate &dd)
130 : QAbstractFileEngine(dd)
131{
132}
133
134/*!
135 \internal
136*/
137ProcessOpenModeResult processOpenModeFlags(QIODevice::OpenMode openMode)
138{
139 ProcessOpenModeResult result;
140 result.ok = false;
141 if ((openMode & QFile::NewOnly) && (openMode & QFile::ExistingOnly)) {
142 qWarning("NewOnly and ExistingOnly are mutually exclusive");
143 result.error = "NewOnly and ExistingOnly are mutually exclusive"_L1;
144 return result;
145 }
146
147 if ((openMode & QFile::ExistingOnly) && !(openMode & (QFile::ReadOnly | QFile::WriteOnly))) {
148 qWarning("ExistingOnly must be specified alongside ReadOnly, WriteOnly, or ReadWrite");
149 result.error =
150 "ExistingOnly must be specified alongside ReadOnly, WriteOnly, or ReadWrite"_L1;
151 return result;
152 }
153
154 // Either Append or NewOnly implies WriteOnly
155 if (openMode & (QFile::Append | QFile::NewOnly))
156 openMode |= QFile::WriteOnly;
157
158 // WriteOnly implies Truncate when ReadOnly, Append, and NewOnly are not set.
159 if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append | QFile::NewOnly)))
160 openMode |= QFile::Truncate;
161
162 result.ok = true;
163 result.openMode = openMode;
164 return result;
165}
166
167/*!
168 Destructs the QFSFileEngine.
169*/
170QFSFileEngine::~QFSFileEngine()
171{
172 Q_D(QFSFileEngine);
173 if (d->closeFileHandle) {
174 if (d->fh) {
175 fclose(d->fh);
176 } else if (d->fd != -1) {
177 QT_CLOSE(d->fd);
178 }
179 }
180 d->unmapAll();
181}
182
183/*!
184 \reimp
185*/
186void QFSFileEngine::setFileName(const QString &file)
187{
188 Q_D(QFSFileEngine);
189 d->init();
190 d->fileEntry = QFileSystemEntry(file);
191}
192
193/*!
194 \reimp
195*/
196bool QFSFileEngine::open(QIODevice::OpenMode openMode,
197 std::optional<QFile::Permissions> permissions)
198{
199 Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
200 "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
201
202 Q_D(QFSFileEngine);
203 if (d->fileEntry.isEmpty()) {
204 qWarning("QFSFileEngine::open: No file name specified");
205 setError(QFile::OpenError, "No file name specified"_L1);
206 return false;
207 }
208
209 const ProcessOpenModeResult res = processOpenModeFlags(openMode);
210 if (!res.ok) {
211 setError(QFileDevice::OpenError, res.error);
212 return false;
213 }
214
215 d->openMode = res.openMode;
216 d->lastFlushFailed = false;
217 d->tried_stat = 0;
218 d->fh = nullptr;
219 d->fd = -1;
220
221 return d->nativeOpen(d->openMode, permissions);
222}
223
224/*!
225 Opens the file handle \a fh in \a openMode mode. Returns \c true on
226 success; otherwise returns \c false.
227*/
228bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHandleFlags handleFlags)
229{
230 Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
231 "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
232
233 Q_D(QFSFileEngine);
234
235 const ProcessOpenModeResult res = processOpenModeFlags(openMode);
236 if (!res.ok) {
237 setError(QFileDevice::OpenError, res.error);
238 return false;
239 }
240
241 d->openMode = res.openMode;
242 d->lastFlushFailed = false;
243 d->closeFileHandle = handleFlags.testAnyFlag(QFile::AutoCloseHandle);
244 d->fileEntry.clear();
245 d->tried_stat = 0;
246 d->fd = -1;
247
248 return d->openFh(d->openMode, fh);
249}
250
251/*!
252 \class QFSFileEnginePrivate
253 \inmodule QtCore
254 \internal
255*/
256
257/*!
258 Opens the file handle \a fh using the open mode \a flags.
259*/
260bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
261{
262 Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
263 "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
264
265 Q_Q(QFSFileEngine);
266 this->fh = fh;
267 fd = -1;
268
269 // Seek to the end when in Append mode.
270 if (openMode & QIODevice::Append) {
271 int ret;
272 do {
273 ret = QT_FSEEK(fh, 0, SEEK_END);
274 } while (ret != 0 && errno == EINTR);
275
276 if (ret != 0) {
277 q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
278 QSystemError::stdString(errno));
279
280 this->openMode = QIODevice::NotOpen;
281 this->fh = nullptr;
282
283 return false;
284 }
285 }
286
287 return true;
288}
289
290/*!
291 Opens the file descriptor \a fd in \a openMode mode. Returns \c true
292 on success; otherwise returns \c false.
293*/
294bool QFSFileEngine::open(QIODevice::OpenMode openMode, int fd, QFile::FileHandleFlags handleFlags)
295{
296 Q_D(QFSFileEngine);
297
298 const ProcessOpenModeResult res = processOpenModeFlags(openMode);
299 if (!res.ok) {
300 setError(QFileDevice::OpenError, res.error);
301 return false;
302 }
303
304 d->openMode = res.openMode;
305 d->lastFlushFailed = false;
306 d->closeFileHandle = handleFlags.testAnyFlag(QFile::AutoCloseHandle);
307 d->fileEntry.clear();
308 d->fh = nullptr;
309 d->fd = -1;
310 d->tried_stat = 0;
311
312 return d->openFd(d->openMode, fd);
313}
314
315
316/*!
317 Opens the file descriptor \a fd to the file engine, using the open mode \a
318 flags.
319*/
320bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
321{
322 Q_Q(QFSFileEngine);
323 this->fd = fd;
324 fh = nullptr;
325
326 // Seek to the end when in Append mode.
327 if (openMode & QFile::Append) {
328 QT_OFF_T ret;
329 do {
330 ret = QT_LSEEK(fd, 0, SEEK_END);
331 } while (ret == -1 && errno == EINTR);
332
333 if (ret == -1) {
334 q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
335 QSystemError::stdString(errno));
336
337 this->openMode = QIODevice::NotOpen;
338 this->fd = -1;
339
340 return false;
341 }
342 }
343
344 return true;
345}
346
347/*!
348 \reimp
349*/
350bool QFSFileEngine::close()
351{
352 Q_D(QFSFileEngine);
353 d->openMode = QIODevice::NotOpen;
354 return d->nativeClose();
355}
356
357/*!
358 \internal
359*/
360bool QFSFileEnginePrivate::closeFdFh()
361{
362 Q_Q(QFSFileEngine);
363 if (fd == -1 && !fh)
364 return false;
365
366 // Flush the file if it's buffered, and if the last flush didn't fail.
367 bool flushed = !fh || (!lastFlushFailed && q->flush());
368 bool closed = true;
369 tried_stat = 0;
370
371 // Close the file if we created the handle.
372 if (closeFileHandle) {
373 int ret;
374
375 if (fh) {
376 // Close buffered file.
377 ret = fclose(fh);
378 } else {
379 // Close unbuffered file.
380 ret = QT_CLOSE(fd);
381 }
382
383 // We must reset these guys regardless; calling close again after a
384 // failed close causes crashes on some systems.
385 fh = nullptr;
386 fd = -1;
387 closed = (ret == 0);
388 }
389
390 // Report errors.
391 if (!flushed || !closed) {
392 if (flushed) {
393 // If not flushed, we want the flush error to fall through.
394 q->setError(QFile::UnspecifiedError, QSystemError::stdString(errno));
395 }
396 return false;
397 }
398
399 return true;
400}
401
402/*!
403 \reimp
404*/
405bool QFSFileEngine::flush()
406{
407 Q_D(QFSFileEngine);
408 if ((d->openMode & QIODevice::WriteOnly) == 0) {
409 // Nothing in the write buffers, so flush succeeds in doing
410 // nothing.
411 return true;
412 }
413 return d->nativeFlush();
414}
415
416/*!
417 \reimp
418*/
419bool QFSFileEngine::syncToDisk()
420{
421 Q_D(QFSFileEngine);
422 if ((d->openMode & QIODevice::WriteOnly) == 0)
423 return true;
424 return d->nativeSyncToDisk();
425}
426
427/*!
428 \internal
429*/
430bool QFSFileEnginePrivate::flushFh()
431{
432 Q_Q(QFSFileEngine);
433
434 // Never try to flush again if the last flush failed. Otherwise you can
435 // get crashes on some systems (AIX).
436 if (lastFlushFailed)
437 return false;
438
439 int ret = fflush(fh);
440
441 lastFlushFailed = (ret != 0);
442 lastIOCommand = QFSFileEnginePrivate::IOFlushCommand;
443
444 if (ret != 0) {
445 q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
446 QSystemError::stdString(errno));
447 return false;
448 }
449 return true;
450}
451
452/*!
453 \reimp
454*/
455qint64 QFSFileEngine::size() const
456{
457 Q_D(const QFSFileEngine);
458 return d->nativeSize();
459}
460
461/*!
462 \internal
463*/
464void QFSFileEnginePrivate::unmapAll()
465{
466 if (!maps.isEmpty()) {
467 const QList<uchar*> keys = maps.keys(); // Make a copy since unmap() modifies the map.
468 for (int i = 0; i < keys.size(); ++i)
469 unmap(keys.at(i));
470 }
471}
472
473#ifndef Q_OS_WIN
474/*!
475 \internal
476*/
477qint64 QFSFileEnginePrivate::sizeFdFh() const
478{
479 Q_Q(const QFSFileEngine);
480 const_cast<QFSFileEngine *>(q)->flush();
481
482 tried_stat = 0;
483 metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
484 if (!doStat(QFileSystemMetaData::SizeAttribute))
485 return 0;
486 return metaData.size();
487}
488#endif
489
490/*!
491 \reimp
492*/
493qint64 QFSFileEngine::pos() const
494{
495 Q_D(const QFSFileEngine);
496 return d->nativePos();
497}
498
499/*!
500 \internal
501*/
502qint64 QFSFileEnginePrivate::posFdFh() const
503{
504 if (fh)
505 return qint64(QT_FTELL(fh));
506 return QT_LSEEK(fd, 0, SEEK_CUR);
507}
508
509/*!
510 \reimp
511*/
512bool QFSFileEngine::seek(qint64 pos)
513{
514 Q_D(QFSFileEngine);
515 return d->nativeSeek(pos);
516}
517
518/*!
519 \reimp
520*/
521QDateTime QFSFileEngine::fileTime(QFile::FileTime time) const
522{
523 Q_D(const QFSFileEngine);
524
525 if (time == QFile::FileAccessTime) {
526 // always refresh for the access time
527 d->metaData.clearFlags(QFileSystemMetaData::AccessTime);
528 }
529
530 if (d->doStat(QFileSystemMetaData::Times))
531 return d->metaData.fileTime(time);
532
533 return QDateTime();
534}
535
536
537/*!
538 \internal
539*/
540bool QFSFileEnginePrivate::seekFdFh(qint64 pos)
541{
542 Q_Q(QFSFileEngine);
543
544 // On Windows' stdlib implementation, the results of calling fread and
545 // fwrite are undefined if not called either in sequence, or if preceded
546 // with a call to fflush().
547 if (lastIOCommand != QFSFileEnginePrivate::IOFlushCommand && !q->flush())
548 return false;
549
550 if (pos < 0 || pos != qint64(QT_OFF_T(pos)))
551 return false;
552
553 if (fh) {
554 // Buffered stdlib mode.
555 int ret;
556 do {
557 ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET);
558 } while (ret != 0 && errno == EINTR);
559
560 if (ret != 0) {
561 q->setError(QFile::ReadError, QSystemError::stdString(errno));
562 return false;
563 }
564 } else {
565 // Unbuffered stdio mode.
566 if (QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) {
567 q->setError(QFile::PositionError, QSystemError::stdString(errno));
568 qWarning("QFile::at: Cannot set file position %lld", pos);
569 return false;
570 }
571 }
572 return true;
573}
574
575/*!
576 \reimp
577*/
578int QFSFileEngine::handle() const
579{
580 Q_D(const QFSFileEngine);
581 return d->nativeHandle();
582}
583
584/*!
585 \reimp
586*/
587qint64 QFSFileEngine::read(char *data, qint64 maxlen)
588{
589 Q_D(QFSFileEngine);
590
591 // On Windows' stdlib implementation, the results of calling fread and
592 // fwrite are undefined if not called either in sequence, or if preceded
593 // with a call to fflush().
594 if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
595 flush();
596 d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
597 }
598
599 return d->nativeRead(data, maxlen);
600}
601
602/*!
603 \internal
604*/
605qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
606{
607 Q_Q(QFSFileEngine);
608
609 if (len < 0 || len != qint64(size_t(len))) {
610 q->setError(QFile::ReadError, QSystemError::stdString(EINVAL));
611 return -1;
612 }
613
614 qint64 readBytes = 0;
615 bool eof = false;
616
617 if (fh) {
618 // Buffered stdlib mode.
619
620 size_t result;
621 do {
622 result = fread(data + readBytes, 1, size_t(len - readBytes), fh);
623 eof = feof(fh); // Doesn't change errno
624 if (eof && result == 0) {
625 // On OS X, this is needed, e.g., if a file was written to
626 // through another stream since our last read. See test
627 // tst_QFile::appendAndRead
628 QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); // re-sync stream.
629 break;
630 }
631 readBytes += result;
632 } while (!eof && (result == 0 ? errno == EINTR : readBytes < len));
633
634 } else if (fd != -1) {
635 // Unbuffered stdio mode.
636
637 SignedIOType result;
638 do {
639 // calculate the chunk size
640 // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
641 // we limit to the size of the signed type, otherwise we could get a negative number as a result
642 quint64 wantedBytes = quint64(len) - quint64(readBytes);
643 UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
644 if (chunkSize > wantedBytes)
645 chunkSize = wantedBytes;
646 result = QT_READ(fd, data + readBytes, chunkSize);
647 } while (result > 0 && (readBytes += result) < len);
648
649 // QT_READ (::read()) returns 0 to indicate end-of-file
650 eof = result == 0;
651 }
652
653 if (!eof && readBytes == 0) {
654 readBytes = -1;
655 q->setError(QFile::ReadError, QSystemError::stdString(errno));
656 }
657
658 return readBytes;
659}
660
661/*!
662 \reimp
663*/
664qint64 QFSFileEngine::readLine(char *data, qint64 maxlen)
665{
666 Q_D(QFSFileEngine);
667
668 // On Windows' stdlib implementation, the results of calling fread and
669 // fwrite are undefined if not called either in sequence, or if preceded
670 // with a call to fflush().
671 if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
672 flush();
673 d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
674 }
675
676 return d->nativeReadLine(data, maxlen);
677}
678
679/*!
680 \internal
681*/
682qint64 QFSFileEnginePrivate::readLineFdFh(char *data, qint64 maxlen)
683{
684 Q_Q(QFSFileEngine);
685 if (!fh)
686 return q->QAbstractFileEngine::readLine(data, maxlen);
687
688 QT_OFF_T oldPos = 0;
689#ifdef Q_OS_WIN
690 bool seq = q->isSequential();
691 if (!seq)
692#endif
693 oldPos = QT_FTELL(fh);
694
695 // QIODevice::readLine() passes maxlen - 1 to QFile::readLineData()
696 // because it has made space for the '\0' at the end of data. But fgets
697 // does the same, so we'd get two '\0' at the end - passing maxlen + 1
698 // solves this.
699 if (!fgets(data, int(maxlen + 1), fh)) {
700 if (!feof(fh)) // Doesn't change errno
701 q->setError(QFile::ReadError, QSystemError::stdString(errno));
702 return -1; // error
703 }
704
705#ifdef Q_OS_WIN
706 if (seq)
707 return qstrlen(data);
708#endif
709
710 qint64 lineLength = QT_FTELL(fh) - oldPos;
711 return lineLength > 0 ? lineLength : qstrlen(data);
712}
713
714/*!
715 \reimp
716*/
717qint64 QFSFileEngine::write(const char *data, qint64 len)
718{
719 Q_D(QFSFileEngine);
720 d->metaData.clearFlags(QFileSystemMetaData::Times);
721
722 // On Windows' stdlib implementation, the results of calling fread and
723 // fwrite are undefined if not called either in sequence, or if preceded
724 // with a call to fflush().
725 if (d->lastIOCommand != QFSFileEnginePrivate::IOWriteCommand) {
726 flush();
727 d->lastIOCommand = QFSFileEnginePrivate::IOWriteCommand;
728 }
729
730 return d->nativeWrite(data, len);
731}
732
733/*!
734 \internal
735*/
736qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
737{
738 Q_Q(QFSFileEngine);
739
740 if (len < 0 || len != qint64(size_t(len))) {
741 q->setError(QFile::WriteError, QSystemError::stdString(EINVAL));
742 return -1;
743 }
744
745 qint64 writtenBytes = 0;
746
747 if (len) { // avoid passing nullptr to fwrite() or QT_WRITE() (UB)
748
749 if (fh) {
750 // Buffered stdlib mode.
751
752 size_t result;
753 do {
754 result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh);
755 writtenBytes += result;
756 } while (result == 0 ? errno == EINTR : writtenBytes < len);
757
758 } else if (fd != -1) {
759 // Unbuffered stdio mode.
760
761 SignedIOType result;
762 do {
763 // calculate the chunk size
764 // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
765 // we limit to the size of the signed type, otherwise we could get a negative number as a result
766 quint64 wantedBytes = quint64(len) - quint64(writtenBytes);
767 UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
768 if (chunkSize > wantedBytes)
769 chunkSize = wantedBytes;
770 result = QT_WRITE(fd, data + writtenBytes, chunkSize);
771 } while (result > 0 && (writtenBytes += result) < len);
772 }
773
774 }
775
776 if (len && writtenBytes == 0) {
777 writtenBytes = -1;
778 q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
779 QSystemError::stdString(errno));
780 } else {
781 // reset the cached size, if any
782 metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
783 }
784
785 return writtenBytes;
786}
787
788#ifndef QT_NO_FILESYSTEMITERATOR
789/*!
790 \internal
791*/
792QAbstractFileEngine::IteratorUniquePtr
793QFSFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters,
794 const QStringList &filterNames)
795{
796 return std::make_unique<QFSFileEngineIterator>(path, filters, filterNames);
797}
798#endif // QT_NO_FILESYSTEMITERATOR
799
800/*!
801 \reimp
802*/
803bool QFSFileEngine::isSequential() const
804{
805 Q_D(const QFSFileEngine);
806 if (d->is_sequential == 0)
807 d->is_sequential = d->nativeIsSequential() ? 1 : 2;
808 return d->is_sequential == 1;
809}
810
811/*!
812 \internal
813*/
814#ifdef Q_OS_UNIX
815bool QFSFileEnginePrivate::isSequentialFdFh() const
816{
817 if (doStat(QFileSystemMetaData::SequentialType))
818 return metaData.isSequential();
819 return true;
820}
821#endif
822
823/*!
824 \reimp
825*/
826bool QFSFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
827{
828 Q_D(QFSFileEngine);
829 if (extension == AtEndExtension && d->fh && isSequential())
830 return feof(d->fh);
831
832 if (extension == MapExtension) {
833 const MapExtensionOption *options = (const MapExtensionOption*)(option);
834 MapExtensionReturn *returnValue = static_cast<MapExtensionReturn*>(output);
835 returnValue->address = d->map(options->offset, options->size, options->flags);
836 return (returnValue->address != nullptr);
837 }
838 if (extension == UnMapExtension) {
839 const UnMapExtensionOption *options = (const UnMapExtensionOption*)option;
840 return d->unmap(options->address);
841 }
842
843 return false;
844}
845
846/*!
847 \reimp
848*/
849bool QFSFileEngine::supportsExtension(Extension extension) const
850{
851 Q_D(const QFSFileEngine);
852 if (extension == AtEndExtension && d->fh && isSequential())
853 return true;
854 if (extension == FastReadLineExtension && d->fh)
855 return true;
856 if (extension == FastReadLineExtension && d->fd != -1 && isSequential())
857 return true;
858 if (extension == UnMapExtension || extension == MapExtension)
859 return true;
860 return false;
861}
862
863/*! \fn QString QFSFileEngine::currentPath(const QString &fileName)
864 For Unix, returns the current working directory for the file
865 engine.
866
867 For Windows, returns the canonicalized form of the current path used
868 by the file engine for the drive specified by \a fileName. On
869 Windows, each drive has its own current directory, so a different
870 path is returned for file names that include different drive names
871 (e.g. A: or C:).
872
873 \sa setCurrentPath()
874*/
875
876/*! \fn QFileInfoList QFSFileEngine::drives()
877 For Windows, returns the list of drives in the file system as a list
878 of QFileInfo objects. On Unix, only the root path is returned.
879 On Windows, this function returns all drives (A:\, C:\, D:\, and so on).
880
881 For Unix, the list contains just the root path "/".
882*/
883
884/*! \fn QString QFSFileEngine::fileName(QAbstractFileEngine::FileName file) const
885 \reimp
886*/
887
888/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
889 \reimp
890*/
891
892/*! \fn bool QFSFileEngine::isRelativePath() const
893 \reimp
894*/
895
896/*! \fn bool QFSFileEngine::link(const QString &newName)
897
898 Creates a link from the file currently specified by fileName() to
899 \a newName. What a link is depends on the underlying filesystem
900 (be it a shortcut on Windows or a symbolic link on Unix). Returns
901 \c true if successful; otherwise returns \c false.
902
903 \note On Windows \a newName is expected to end with .lnk as the filename
904 extension.
905*/
906
907
908/*! \fn uint QFSFileEngine::ownerId(QAbstractFileEngine::FileOwner own) const
909 In Unix, if stat() is successful, the \c uid is returned if
910 \a own is the owner. Otherwise the \c gid is returned. If stat()
911 is unsuccessful, -2 is reuturned.
912
913 For Windows, -2 is always returned.
914*/
915
916/*! \fn QString QFSFileEngine::owner(QAbstractFileEngine::FileOwner own) const
917 \reimp
918*/
919
920/*!
921 For Windows or Apple platforms, copy the file to file \a copyName.
922
923 Not implemented for other Unix platforms.
924*/
925bool QFSFileEngine::copy(const QString &copyName)
926{
927 Q_D(QFSFileEngine);
928 QSystemError error;
929 bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(copyName), error);
930 if (!ret)
931 setError(QFile::CopyError, error.toString());
932 return ret;
933}
934
935/*!
936 \reimp
937*/
938bool QFSFileEngine::remove()
939{
940 Q_D(QFSFileEngine);
941 QSystemError error;
942 bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
943 if (!ret)
944 setError(QFile::RemoveError, error.toString());
945 else
946 d->metaData.clear();
947 return ret;
948}
949
950/*
951 An alternative to setFileName() when you have already constructed
952 a QFileSystemEntry.
953*/
954void QFSFileEngine::setFileEntry(QFileSystemEntry &&entry)
955{
956 Q_D(QFSFileEngine);
957 d->init();
958 d->fileEntry = std::move(entry);
959}
960
961bool QFSFileEngine::rename_helper(const QString &newName, RenameMode mode)
962{
963 Q_D(QFSFileEngine);
964
965 auto func = mode == Rename ? QFileSystemEngine::renameFile
966 : QFileSystemEngine::renameOverwriteFile;
967 QSystemError error;
968 auto newEntry = QFileSystemEntry(newName);
969 const bool ret = func(d->fileEntry, newEntry, error);
970 if (!ret) {
971 setError(QFile::RenameError, error.toString());
972 return false;
973 }
974 setFileEntry(std::move(newEntry));
975 return true;
976}
977
978/*!
979 \reimp
980*/
981bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories,
982 std::optional<QFile::Permissions> permissions) const
983{
984 return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories,
985 permissions);
986}
987
988/*!
989 \reimp
990*/
991bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
992{
993 return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
994}
995
996
997/*!
998 Sets the current path (e.g., for QDir), to \a path. Returns \c true if the
999 new path exists; otherwise this function does nothing, and returns \c false.
1000
1001 \sa currentPath()
1002*/
1003bool QFSFileEngine::setCurrentPath(const QString &path)
1004{
1005 return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
1006}
1007
1008/*!
1009 Returns whether the file system considers the file name to be
1010 case sensitive.
1011*/
1012bool QFSFileEngine::caseSensitive() const
1013{
1014 Q_D(const QFSFileEngine);
1015 return QFileSystemEngine::isCaseSensitive(d->fileEntry, d->metaData);
1016}
1017
1018/*! \fn bool QFSFileEngine::setPermissions(uint perms)
1019 \reimp
1020*/
1021
1022/*! \fn bool QFSFileEngine::setSize(qint64 size)
1023 \reimp
1024*/
1025
1026/*! \fn QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFileEngine::FileFlags type) const
1027 \internal
1028*/
1029
1030QT_END_NAMESPACE
1031
1032#endif // QT_NO_FSFILEENGINE
size_t UnsignedIOType
ssize_t SignedIOType
ProcessOpenModeResult processOpenModeFlags(QIODevice::OpenMode openMode)