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 Opens the file handle \a fh using the open mode \a flags.
253*/
254bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
255{
256 Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
257 "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
258
259 Q_Q(QFSFileEngine);
260 this->fh = fh;
261 fd = -1;
262
263 // Seek to the end when in Append mode.
264 if (openMode & QIODevice::Append) {
265 int ret;
266 do {
267 ret = QT_FSEEK(fh, 0, SEEK_END);
268 } while (ret != 0 && errno == EINTR);
269
270 if (ret != 0) {
271 q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
272 QSystemError::stdString(errno));
273
274 this->openMode = QIODevice::NotOpen;
275 this->fh = nullptr;
276
277 return false;
278 }
279 }
280
281 return true;
282}
283
284/*!
285 Opens the file descriptor \a fd in \a openMode mode. Returns \c true
286 on success; otherwise returns \c false.
287*/
288bool QFSFileEngine::open(QIODevice::OpenMode openMode, int fd, QFile::FileHandleFlags handleFlags)
289{
290 Q_D(QFSFileEngine);
291
292 const ProcessOpenModeResult res = processOpenModeFlags(openMode);
293 if (!res.ok) {
294 setError(QFileDevice::OpenError, res.error);
295 return false;
296 }
297
298 d->openMode = res.openMode;
299 d->lastFlushFailed = false;
300 d->closeFileHandle = handleFlags.testAnyFlag(QFile::AutoCloseHandle);
301 d->fileEntry.clear();
302 d->fh = nullptr;
303 d->fd = -1;
304 d->tried_stat = 0;
305
306 return d->openFd(d->openMode, fd);
307}
308
309
310/*!
311 Opens the file descriptor \a fd to the file engine, using the open mode \a
312 flags.
313*/
314bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
315{
316 Q_Q(QFSFileEngine);
317 this->fd = fd;
318 fh = nullptr;
319
320 // Seek to the end when in Append mode.
321 if (openMode & QFile::Append) {
322 QT_OFF_T ret;
323 do {
324 ret = QT_LSEEK(fd, 0, SEEK_END);
325 } while (ret == -1 && errno == EINTR);
326
327 if (ret == -1) {
328 q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
329 QSystemError::stdString(errno));
330
331 this->openMode = QIODevice::NotOpen;
332 this->fd = -1;
333
334 return false;
335 }
336 }
337
338 return true;
339}
340
341/*!
342 \reimp
343*/
344bool QFSFileEngine::close()
345{
346 Q_D(QFSFileEngine);
347 d->openMode = QIODevice::NotOpen;
348 return d->nativeClose();
349}
350
351/*!
352 \internal
353*/
354bool QFSFileEnginePrivate::closeFdFh()
355{
356 Q_Q(QFSFileEngine);
357 if (fd == -1 && !fh)
358 return false;
359
360 // Flush the file if it's buffered, and if the last flush didn't fail.
361 bool flushed = !fh || (!lastFlushFailed && q->flush());
362 bool closed = true;
363 tried_stat = 0;
364
365 // Close the file if we created the handle.
366 if (closeFileHandle) {
367 int ret;
368
369 if (fh) {
370 // Close buffered file.
371 ret = fclose(fh);
372 } else {
373 // Close unbuffered file.
374 ret = QT_CLOSE(fd);
375 }
376
377 // We must reset these guys regardless; calling close again after a
378 // failed close causes crashes on some systems.
379 fh = nullptr;
380 fd = -1;
381 closed = (ret == 0);
382 }
383
384 // Report errors.
385 if (!flushed || !closed) {
386 if (flushed) {
387 // If not flushed, we want the flush error to fall through.
388 q->setError(QFile::UnspecifiedError, QSystemError::stdString(errno));
389 }
390 return false;
391 }
392
393 return true;
394}
395
396/*!
397 \reimp
398*/
399bool QFSFileEngine::flush()
400{
401 Q_D(QFSFileEngine);
402 if ((d->openMode & QIODevice::WriteOnly) == 0) {
403 // Nothing in the write buffers, so flush succeeds in doing
404 // nothing.
405 return true;
406 }
407 return d->nativeFlush();
408}
409
410/*!
411 \reimp
412*/
413bool QFSFileEngine::syncToDisk()
414{
415 Q_D(QFSFileEngine);
416 if ((d->openMode & QIODevice::WriteOnly) == 0)
417 return true;
418 return d->nativeSyncToDisk();
419}
420
421/*!
422 \internal
423*/
424bool QFSFileEnginePrivate::flushFh()
425{
426 Q_Q(QFSFileEngine);
427
428 // Never try to flush again if the last flush failed. Otherwise you can
429 // get crashes on some systems (AIX).
430 if (lastFlushFailed)
431 return false;
432
433 int ret = fflush(fh);
434
435 lastFlushFailed = (ret != 0);
436 lastIOCommand = QFSFileEnginePrivate::IOFlushCommand;
437
438 if (ret != 0) {
439 q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
440 QSystemError::stdString(errno));
441 return false;
442 }
443 return true;
444}
445
446/*!
447 \reimp
448*/
449qint64 QFSFileEngine::size() const
450{
451 Q_D(const QFSFileEngine);
452 return d->nativeSize();
453}
454
455/*!
456 \internal
457*/
458void QFSFileEnginePrivate::unmapAll()
459{
460 if (!maps.isEmpty()) {
461 const QList<uchar*> keys = maps.keys(); // Make a copy since unmap() modifies the map.
462 for (int i = 0; i < keys.size(); ++i)
463 unmap(keys.at(i));
464 }
465}
466
467#ifndef Q_OS_WIN
468/*!
469 \internal
470*/
471qint64 QFSFileEnginePrivate::sizeFdFh() const
472{
473 Q_Q(const QFSFileEngine);
474 const_cast<QFSFileEngine *>(q)->flush();
475
476 tried_stat = 0;
477 metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
478 if (!doStat(QFileSystemMetaData::SizeAttribute))
479 return 0;
480 return metaData.size();
481}
482#endif
483
484/*!
485 \reimp
486*/
487qint64 QFSFileEngine::pos() const
488{
489 Q_D(const QFSFileEngine);
490 return d->nativePos();
491}
492
493/*!
494 \internal
495*/
496qint64 QFSFileEnginePrivate::posFdFh() const
497{
498 if (fh)
499 return qint64(QT_FTELL(fh));
500 return QT_LSEEK(fd, 0, SEEK_CUR);
501}
502
503/*!
504 \reimp
505*/
506bool QFSFileEngine::seek(qint64 pos)
507{
508 Q_D(QFSFileEngine);
509 return d->nativeSeek(pos);
510}
511
512/*!
513 \reimp
514*/
515QDateTime QFSFileEngine::fileTime(QFile::FileTime time) const
516{
517 Q_D(const QFSFileEngine);
518
519 if (time == QFile::FileAccessTime) {
520 // always refresh for the access time
521 d->metaData.clearFlags(QFileSystemMetaData::AccessTime);
522 }
523
524 if (d->doStat(QFileSystemMetaData::Times))
525 return d->metaData.fileTime(time);
526
527 return QDateTime();
528}
529
530
531/*!
532 \internal
533*/
534bool QFSFileEnginePrivate::seekFdFh(qint64 pos)
535{
536 Q_Q(QFSFileEngine);
537
538 // On Windows' stdlib implementation, the results of calling fread and
539 // fwrite are undefined if not called either in sequence, or if preceded
540 // with a call to fflush().
541 if (lastIOCommand != QFSFileEnginePrivate::IOFlushCommand && !q->flush())
542 return false;
543
544 if (pos < 0 || pos != qint64(QT_OFF_T(pos)))
545 return false;
546
547 if (fh) {
548 // Buffered stdlib mode.
549 int ret;
550 do {
551 ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET);
552 } while (ret != 0 && errno == EINTR);
553
554 if (ret != 0) {
555 q->setError(QFile::ReadError, QSystemError::stdString(errno));
556 return false;
557 }
558 } else {
559 // Unbuffered stdio mode.
560 if (QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) {
561 q->setError(QFile::PositionError, QSystemError::stdString(errno));
562 qWarning("QFile::at: Cannot set file position %lld", pos);
563 return false;
564 }
565 }
566 return true;
567}
568
569/*!
570 \reimp
571*/
572int QFSFileEngine::handle() const
573{
574 Q_D(const QFSFileEngine);
575 return d->nativeHandle();
576}
577
578/*!
579 \reimp
580*/
581qint64 QFSFileEngine::read(char *data, qint64 maxlen)
582{
583 Q_D(QFSFileEngine);
584
585 // On Windows' stdlib implementation, the results of calling fread and
586 // fwrite are undefined if not called either in sequence, or if preceded
587 // with a call to fflush().
588 if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
589 flush();
590 d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
591 }
592
593 return d->nativeRead(data, maxlen);
594}
595
596/*!
597 \internal
598*/
599qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
600{
601 Q_Q(QFSFileEngine);
602
603 if (len < 0 || len != qint64(size_t(len))) {
604 q->setError(QFile::ReadError, QSystemError::stdString(EINVAL));
605 return -1;
606 }
607
608 qint64 readBytes = 0;
609 bool eof = false;
610
611 if (fh) {
612 // Buffered stdlib mode.
613
614 size_t result;
615 do {
616 result = fread(data + readBytes, 1, size_t(len - readBytes), fh);
617 eof = feof(fh); // Doesn't change errno
618 if (eof && result == 0) {
619 // On OS X, this is needed, e.g., if a file was written to
620 // through another stream since our last read. See test
621 // tst_QFile::appendAndRead
622 QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); // re-sync stream.
623 break;
624 }
625 readBytes += result;
626 } while (!eof && (result == 0 ? errno == EINTR : readBytes < len));
627
628 } else if (fd != -1) {
629 // Unbuffered stdio mode.
630
631 SignedIOType result;
632 do {
633 // calculate the chunk size
634 // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
635 // we limit to the size of the signed type, otherwise we could get a negative number as a result
636 quint64 wantedBytes = quint64(len) - quint64(readBytes);
637 UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
638 if (chunkSize > wantedBytes)
639 chunkSize = wantedBytes;
640 result = QT_READ(fd, data + readBytes, chunkSize);
641 } while (result > 0 && (readBytes += result) < len);
642
643 // QT_READ (::read()) returns 0 to indicate end-of-file
644 eof = result == 0;
645 }
646
647 if (!eof && readBytes == 0) {
648 readBytes = -1;
649 q->setError(QFile::ReadError, QSystemError::stdString(errno));
650 }
651
652 return readBytes;
653}
654
655/*!
656 \reimp
657*/
658qint64 QFSFileEngine::readLine(char *data, qint64 maxlen)
659{
660 Q_D(QFSFileEngine);
661
662 // On Windows' stdlib implementation, the results of calling fread and
663 // fwrite are undefined if not called either in sequence, or if preceded
664 // with a call to fflush().
665 if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
666 flush();
667 d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
668 }
669
670 return d->nativeReadLine(data, maxlen);
671}
672
673/*!
674 \internal
675*/
676qint64 QFSFileEnginePrivate::readLineFdFh(char *data, qint64 maxlen)
677{
678 Q_Q(QFSFileEngine);
679 if (!fh)
680 return q->QAbstractFileEngine::readLine(data, maxlen);
681
682 QT_OFF_T oldPos = 0;
683#ifdef Q_OS_WIN
684 bool seq = q->isSequential();
685 if (!seq)
686#endif
687 oldPos = QT_FTELL(fh);
688
689 // QIODevice::readLine() passes maxlen - 1 to QFile::readLineData()
690 // because it has made space for the '\0' at the end of data. But fgets
691 // does the same, so we'd get two '\0' at the end - passing maxlen + 1
692 // solves this.
693 if (!fgets(data, int(maxlen + 1), fh)) {
694 if (!feof(fh)) // Doesn't change errno
695 q->setError(QFile::ReadError, QSystemError::stdString(errno));
696 return -1; // error
697 }
698
699#ifdef Q_OS_WIN
700 if (seq)
701 return qstrlen(data);
702#endif
703
704 qint64 lineLength = QT_FTELL(fh) - oldPos;
705 return lineLength > 0 ? lineLength : qstrlen(data);
706}
707
708/*!
709 \reimp
710*/
711qint64 QFSFileEngine::write(const char *data, qint64 len)
712{
713 Q_D(QFSFileEngine);
714 d->metaData.clearFlags(QFileSystemMetaData::Times);
715
716 // On Windows' stdlib implementation, the results of calling fread and
717 // fwrite are undefined if not called either in sequence, or if preceded
718 // with a call to fflush().
719 if (d->lastIOCommand != QFSFileEnginePrivate::IOWriteCommand) {
720 flush();
721 d->lastIOCommand = QFSFileEnginePrivate::IOWriteCommand;
722 }
723
724 return d->nativeWrite(data, len);
725}
726
727/*!
728 \internal
729*/
730qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
731{
732 Q_Q(QFSFileEngine);
733
734 if (len < 0 || len != qint64(size_t(len))) {
735 q->setError(QFile::WriteError, QSystemError::stdString(EINVAL));
736 return -1;
737 }
738
739 qint64 writtenBytes = 0;
740
741 if (len) { // avoid passing nullptr to fwrite() or QT_WRITE() (UB)
742
743 if (fh) {
744 // Buffered stdlib mode.
745
746 size_t result;
747 do {
748 result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh);
749 writtenBytes += result;
750 } while (result == 0 ? errno == EINTR : writtenBytes < len);
751
752 } else if (fd != -1) {
753 // Unbuffered stdio mode.
754
755 SignedIOType result;
756 do {
757 // calculate the chunk size
758 // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
759 // we limit to the size of the signed type, otherwise we could get a negative number as a result
760 quint64 wantedBytes = quint64(len) - quint64(writtenBytes);
761 UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
762 if (chunkSize > wantedBytes)
763 chunkSize = wantedBytes;
764 result = QT_WRITE(fd, data + writtenBytes, chunkSize);
765 } while (result > 0 && (writtenBytes += result) < len);
766 }
767
768 }
769
770 if (len && writtenBytes == 0) {
771 writtenBytes = -1;
772 q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
773 QSystemError::stdString(errno));
774 } else {
775 // reset the cached size, if any
776 metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
777 }
778
779 return writtenBytes;
780}
781
782#ifndef QT_NO_FILESYSTEMITERATOR
783/*!
784 \internal
785*/
786QAbstractFileEngine::IteratorUniquePtr
787QFSFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters,
788 const QStringList &filterNames)
789{
790 return std::make_unique<QFSFileEngineIterator>(path, filters, filterNames);
791}
792#endif // QT_NO_FILESYSTEMITERATOR
793
794/*!
795 \reimp
796*/
797bool QFSFileEngine::isSequential() const
798{
799 Q_D(const QFSFileEngine);
800 if (d->is_sequential == 0)
801 d->is_sequential = d->nativeIsSequential() ? 1 : 2;
802 return d->is_sequential == 1;
803}
804
805/*!
806 \internal
807*/
808#ifdef Q_OS_UNIX
809bool QFSFileEnginePrivate::isSequentialFdFh() const
810{
811 if (doStat(QFileSystemMetaData::SequentialType))
812 return metaData.isSequential();
813 return true;
814}
815#endif
816
817/*!
818 \reimp
819*/
820bool QFSFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
821{
822 Q_D(QFSFileEngine);
823 if (extension == AtEndExtension && d->fh && isSequential())
824 return feof(d->fh);
825
826 if (extension == MapExtension) {
827 const MapExtensionOption *options = (const MapExtensionOption*)(option);
828 MapExtensionReturn *returnValue = static_cast<MapExtensionReturn*>(output);
829 returnValue->address = d->map(options->offset, options->size, options->flags);
830 return (returnValue->address != nullptr);
831 }
832 if (extension == UnMapExtension) {
833 const UnMapExtensionOption *options = (const UnMapExtensionOption*)option;
834 return d->unmap(options->address);
835 }
836
837 return false;
838}
839
840/*!
841 \reimp
842*/
843bool QFSFileEngine::supportsExtension(Extension extension) const
844{
845 Q_D(const QFSFileEngine);
846 if (extension == AtEndExtension && d->fh && isSequential())
847 return true;
848 if (extension == FastReadLineExtension && d->fh)
849 return true;
850 if (extension == FastReadLineExtension && d->fd != -1 && isSequential())
851 return true;
852 if (extension == UnMapExtension || extension == MapExtension)
853 return true;
854 return false;
855}
856
857/*! \fn QString QFSFileEngine::currentPath(const QString &fileName)
858 For Unix, returns the current working directory for the file
859 engine.
860
861 For Windows, returns the canonicalized form of the current path used
862 by the file engine for the drive specified by \a fileName. On
863 Windows, each drive has its own current directory, so a different
864 path is returned for file names that include different drive names
865 (e.g. A: or C:).
866
867 \sa setCurrentPath()
868*/
869
870/*! \fn QFileInfoList QFSFileEngine::drives()
871 For Windows, returns the list of drives in the file system as a list
872 of QFileInfo objects. On Unix, only the root path is returned.
873 On Windows, this function returns all drives (A:\, C:\, D:\, and so on).
874
875 For Unix, the list contains just the root path "/".
876*/
877
878/*! \fn QString QFSFileEngine::fileName(QAbstractFileEngine::FileName file) const
879 \reimp
880*/
881
882/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
883 \reimp
884*/
885
886/*! \fn bool QFSFileEngine::isRelativePath() const
887 \reimp
888*/
889
890/*! \fn bool QFSFileEngine::link(const QString &newName)
891
892 Creates a link from the file currently specified by fileName() to
893 \a newName. What a link is depends on the underlying filesystem
894 (be it a shortcut on Windows or a symbolic link on Unix). Returns
895 \c true if successful; otherwise returns \c false.
896
897 \note On Windows \a newName is expected to end with .lnk as the filename
898 extension.
899*/
900
901
902/*! \fn uint QFSFileEngine::ownerId(QAbstractFileEngine::FileOwner own) const
903 In Unix, if stat() is successful, the \c uid is returned if
904 \a own is the owner. Otherwise the \c gid is returned. If stat()
905 is unsuccessful, -2 is reuturned.
906
907 For Windows, -2 is always returned.
908*/
909
910/*! \fn QString QFSFileEngine::owner(QAbstractFileEngine::FileOwner own) const
911 \reimp
912*/
913
914/*!
915 For Windows or Apple platforms, copy the file to file \a copyName.
916
917 Not implemented for other Unix platforms.
918*/
919bool QFSFileEngine::copy(const QString &copyName)
920{
921 Q_D(QFSFileEngine);
922 QSystemError error;
923 bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(copyName), error);
924 if (!ret)
925 setError(QFile::CopyError, error.toString());
926 return ret;
927}
928
929/*!
930 \reimp
931*/
932bool QFSFileEngine::remove()
933{
934 Q_D(QFSFileEngine);
935 QSystemError error;
936 bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
937 if (!ret)
938 setError(QFile::RemoveError, error.toString());
939 else
940 d->metaData.clear();
941 return ret;
942}
943
944/*
945 An alternative to setFileName() when you have already constructed
946 a QFileSystemEntry.
947*/
948void QFSFileEngine::setFileEntry(QFileSystemEntry &&entry)
949{
950 Q_D(QFSFileEngine);
951 d->init();
952 d->fileEntry = std::move(entry);
953}
954
955bool QFSFileEngine::rename_helper(const QString &newName, RenameMode mode)
956{
957 Q_D(QFSFileEngine);
958
959 auto func = mode == Rename ? QFileSystemEngine::renameFile
960 : QFileSystemEngine::renameOverwriteFile;
961 QSystemError error;
962 auto newEntry = QFileSystemEntry(newName);
963 const bool ret = func(d->fileEntry, newEntry, error);
964 if (!ret) {
965 setError(QFile::RenameError, error.toString());
966 return false;
967 }
968 setFileEntry(std::move(newEntry));
969 return true;
970}
971
972/*!
973 \reimp
974*/
975bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories,
976 std::optional<QFile::Permissions> permissions) const
977{
978 return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories,
979 permissions);
980}
981
982/*!
983 \reimp
984*/
985bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
986{
987 return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
988}
989
990
991/*!
992 Sets the current path (e.g., for QDir), to \a path. Returns \c true if the
993 new path exists; otherwise this function does nothing, and returns \c false.
994
995 \sa currentPath()
996*/
997bool QFSFileEngine::setCurrentPath(const QString &path)
998{
999 return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
1000}
1001
1002/*!
1003 Returns whether the file system considers the file name to be
1004 case sensitive.
1005*/
1006bool QFSFileEngine::caseSensitive() const
1007{
1008 Q_D(const QFSFileEngine);
1009 return QFileSystemEngine::isCaseSensitive(d->fileEntry, d->metaData);
1010}
1011
1012/*! \fn bool QFSFileEngine::setPermissions(uint perms)
1013 \reimp
1014*/
1015
1016/*! \fn bool QFSFileEngine::setSize(qint64 size)
1017 \reimp
1018*/
1019
1020/*! \fn QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFileEngine::FileFlags type) const
1021 \internal
1022*/
1023
1024QT_END_NAMESPACE
1025
1026#endif // QT_NO_FSFILEENGINE
size_t UnsignedIOType
ssize_t SignedIOType
ProcessOpenModeResult processOpenModeFlags(QIODevice::OpenMode openMode)