1// Copyright (C) 2022 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 "private/qabstractfileengine_p.h"
5#include "private/qfsfileengine_p.h"
6#ifdef QT_BUILD_CORE_LIB
7#include "private/qresource_p.h"
8#endif
9#include "qdatetime.h"
10#include "qreadwritelock.h"
11#include "qvariant.h"
12// built-in handlers
13#include "qdiriterator.h"
14#include "qstringbuilder.h"
15
16#include <QtCore/private/qfilesystementry_p.h>
17#include <QtCore/private/qfilesystemmetadata_p.h>
18#include <QtCore/private/qfilesystemengine_p.h>
19
20QT_BEGIN_NAMESPACE
21
22/*!
23 \class QAbstractFileEngineHandler
24 \inmodule QtCore
25 \reentrant
26 \internal
27
28 \brief The QAbstractFileEngineHandler class provides a way to register
29 custom file engines with your application.
30
31 \ingroup io
32 \since 4.1
33
34 QAbstractFileEngineHandler is a factory for creating QAbstractFileEngine
35 objects (file engines), which are used internally by QFile, QFileInfo, and
36 QDir when working with files and directories.
37
38 When you open a file, Qt chooses a suitable file engine by passing the
39 file name from QFile or QDir through an internal list of registered file
40 engine handlers. The first handler to recognize the file name is used to
41 create the engine. Qt provides internal file engines for working with
42 regular files and resources, but you can also register your own
43 QAbstractFileEngine subclasses.
44
45 To install an application-specific file engine, you subclass
46 QAbstractFileEngineHandler and reimplement create(). When you instantiate
47 the handler (e.g. by creating an instance on the stack or on the heap), it
48 will automatically register with Qt. (The latest registered handler takes
49 precedence over existing handlers.)
50
51 For example:
52
53 \snippet code/src_corelib_io_qabstractfileengine.cpp 0
54
55 When the handler is destroyed, it is automatically removed from Qt.
56
57 The most common approach to registering a handler is to create an instance
58 as part of the start-up phase of your application. It is also possible to
59 limit the scope of the file engine handler to a particular area of
60 interest (e.g. a special file dialog that needs a custom file engine). By
61 creating the handler inside a local scope, you can precisely control the
62 area in which your engine will be applied without disturbing file
63 operations in other parts of your application.
64
65 \sa QAbstractFileEngine, QAbstractFileEngine::create()
66*/
67
68Q_CONSTINIT static QBasicAtomicInt qt_file_engine_handlers_in_use = Q_BASIC_ATOMIC_INITIALIZER(false);
69
70/*
71 All application-wide handlers are stored in this list. The mutex must be
72 acquired to ensure thread safety.
73 */
74Q_GLOBAL_STATIC(QReadWriteLock, fileEngineHandlerMutex, QReadWriteLock::Recursive)
75Q_CONSTINIT static bool qt_abstractfileenginehandlerlist_shutDown = false;
76class QAbstractFileEngineHandlerList : public QList<QAbstractFileEngineHandler *>
77{
78public:
79 ~QAbstractFileEngineHandlerList()
80 {
81 QWriteLocker locker(fileEngineHandlerMutex());
82 qt_abstractfileenginehandlerlist_shutDown = true;
83 }
84};
85Q_GLOBAL_STATIC(QAbstractFileEngineHandlerList, fileEngineHandlers)
86
87/*!
88 Constructs a file handler and registers it with Qt. Once created this
89 handler's create() function will be called (along with all the other
90 handlers) for any paths used. The most recently created handler that
91 recognizes the given path (i.e. that returns a QAbstractFileEngine) is
92 used for the new path.
93
94 \sa create()
95 */
96QAbstractFileEngineHandler::QAbstractFileEngineHandler()
97{
98 QWriteLocker locker(fileEngineHandlerMutex());
99 qt_file_engine_handlers_in_use.storeRelaxed(newValue: true);
100 fileEngineHandlers()->prepend(t: this);
101}
102
103/*!
104 Destroys the file handler. This will automatically unregister the handler
105 from Qt.
106 */
107QAbstractFileEngineHandler::~QAbstractFileEngineHandler()
108{
109 QWriteLocker locker(fileEngineHandlerMutex());
110 // Remove this handler from the handler list only if the list is valid.
111 if (!qt_abstractfileenginehandlerlist_shutDown) {
112 QAbstractFileEngineHandlerList *handlers = fileEngineHandlers();
113 handlers->removeOne(t: this);
114 if (handlers->isEmpty())
115 qt_file_engine_handlers_in_use.storeRelaxed(newValue: false);
116 }
117}
118
119/*
120 \internal
121
122 Handles calls to custom file engine handlers.
123*/
124QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path)
125{
126 if (qt_file_engine_handlers_in_use.loadRelaxed()) {
127 QReadLocker locker(fileEngineHandlerMutex());
128
129 // check for registered handlers that can load the file
130 for (QAbstractFileEngineHandler *handler : std::as_const(t&: *fileEngineHandlers())) {
131 if (QAbstractFileEngine *engine = handler->create(fileName: path))
132 return engine;
133 }
134 }
135
136 return nullptr;
137}
138
139/*!
140 \fn QAbstractFileEngine *QAbstractFileEngineHandler::create(const QString &fileName) const
141
142 Creates a file engine for file \a fileName. Returns 0 if this
143 file handler cannot handle \a fileName.
144
145 Example:
146
147 \snippet code/src_corelib_io_qabstractfileengine.cpp 1
148
149 \sa QAbstractFileEngine::create()
150*/
151
152/*!
153 Creates and returns a QAbstractFileEngine suitable for processing \a
154 fileName.
155
156 You should not need to call this function; use QFile, QFileInfo or
157 QDir directly instead.
158
159 If you reimplemnt this function, it should only return file
160 engines that knows how to handle \a fileName; otherwise, it should
161 return 0.
162
163 \sa QAbstractFileEngineHandler
164*/
165QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
166{
167 QFileSystemEntry entry(fileName);
168 QFileSystemMetaData metaData;
169 QAbstractFileEngine *engine = QFileSystemEngine::resolveEntryAndCreateLegacyEngine(entry, data&: metaData);
170
171#ifndef QT_NO_FSFILEENGINE
172 if (!engine)
173 // fall back to regular file engine
174 return new QFSFileEngine(entry.filePath());
175#endif
176
177 return engine;
178}
179
180/*!
181 \class QAbstractFileEngine
182 \inmodule QtCore
183 \reentrant
184 \internal
185
186 \brief The QAbstractFileEngine class provides an abstraction for accessing
187 the filesystem.
188
189 \ingroup io
190 \since 4.1
191
192 The QDir, QFile, and QFileInfo classes all make use of a
193 QAbstractFileEngine internally. If you create your own QAbstractFileEngine
194 subclass (and register it with Qt by creating a QAbstractFileEngineHandler
195 subclass), your file engine will be used when the path is one that your
196 file engine handles.
197
198 A QAbstractFileEngine refers to one file or one directory. If the referent
199 is a file, the setFileName(), rename(), and remove() functions are
200 applicable. If the referent is a directory the mkdir(), rmdir(), and
201 entryList() functions are applicable. In all cases the caseSensitive(),
202 isRelativePath(), fileFlags(), ownerId(), owner(), and fileTime()
203 functions are applicable.
204
205 A QAbstractFileEngine subclass can be created to do synchronous network I/O
206 based file system operations, local file system operations, or to operate
207 as a resource system to access file based resources.
208
209 \sa QAbstractFileEngineHandler
210*/
211
212/*!
213 \enum QAbstractFileEngine::FileName
214
215 These values are used to request a file name in a particular
216 format.
217
218 \value DefaultName The same filename that was passed to the
219 QAbstractFileEngine.
220 \value BaseName The name of the file excluding the path.
221 \value PathName The path to the file excluding the base name.
222 \value AbsoluteName The absolute path to the file (including
223 the base name).
224 \value AbsolutePathName The absolute path to the file (excluding
225 the base name).
226 \value AbsoluteLinkTarget The full file name of the file that this file is a
227 link to. (This will be empty if this file is not a link.)
228 \value RawLinkPath The raw link path of the file that this file is a
229 link to. (This will be empty if this file is not a link.)
230 \value CanonicalName Often very similar to AbsoluteLinkTarget. Will return the true path to the file.
231 \value CanonicalPathName Same as CanonicalName, excluding the base name.
232 \value BundleName Returns the name of the bundle implies BundleType is set.
233 \value JunctionName The full name of the directory that this NTFS junction
234 is linked to. (This will be empty if this file is not an NTFS junction.)
235
236 \omitvalue NFileNames
237
238 \sa fileName(), setFileName()
239*/
240
241/*!
242 \enum QAbstractFileEngine::FileFlag
243
244 The permissions and types of a file, suitable for OR'ing together.
245
246 \value ReadOwnerPerm The owner of the file has permission to read
247 it.
248 \value WriteOwnerPerm The owner of the file has permission to
249 write to it.
250 \value ExeOwnerPerm The owner of the file has permission to
251 execute it.
252 \value ReadUserPerm The current user has permission to read the
253 file.
254 \value WriteUserPerm The current user has permission to write to
255 the file.
256 \value ExeUserPerm The current user has permission to execute the
257 file.
258 \value ReadGroupPerm Members of the current user's group have
259 permission to read the file.
260 \value WriteGroupPerm Members of the current user's group have
261 permission to write to the file.
262 \value ExeGroupPerm Members of the current user's group have
263 permission to execute the file.
264 \value ReadOtherPerm All users have permission to read the file.
265 \value WriteOtherPerm All users have permission to write to the
266 file.
267 \value ExeOtherPerm All users have permission to execute the file.
268
269 \value LinkType The file is a link to another file (or link) in
270 the file system (i.e. not a file or directory).
271 \value FileType The file is a regular file to the file system
272 (i.e. not a link or directory)
273 \value BundleType \macos and iOS: the file is a bundle; implies DirectoryType
274 \value DirectoryType The file is a directory in the file system
275 (i.e. not a link or file).
276
277 \value HiddenFlag The file is hidden.
278 \value ExistsFlag The file actually exists in the file system.
279 \value RootFlag The file or the file pointed to is the root of the filesystem.
280 \value LocalDiskFlag The file resides on the local disk and can be passed to standard file functions.
281 \value Refresh Passing this flag will force the file engine to refresh all flags.
282
283 \omitvalue PermsMask
284 \omitvalue TypesMask
285 \omitvalue FlagsMask
286 \omitvalue FileInfoAll
287
288 \sa fileFlags(), setFileName()
289*/
290
291/*!
292 \enum QAbstractFileEngine::FileTime
293
294 These are used by the fileTime() function.
295
296 \value BirthTime When the file was born (created).
297 \value MetadataChangeTime When the file's metadata was last changed.
298 \value ModificationTime When the file was most recently modified.
299 \value AccessTime When the file was most recently accessed (e.g.
300 read or written to).
301
302 \sa setFileName()
303*/
304
305/*!
306 \enum QAbstractFileEngine::FileOwner
307
308 \value OwnerUser The user who owns the file.
309 \value OwnerGroup The group who owns the file.
310
311 \sa owner(), ownerId(), setFileName()
312*/
313
314/*!
315 Constructs a new QAbstractFileEngine that does not refer to any file or directory.
316
317 \sa setFileName()
318 */
319QAbstractFileEngine::QAbstractFileEngine() : d_ptr(new QAbstractFileEnginePrivate)
320{
321 d_ptr->q_ptr = this;
322}
323
324/*!
325 \internal
326
327 Constructs a QAbstractFileEngine.
328 */
329QAbstractFileEngine::QAbstractFileEngine(QAbstractFileEnginePrivate &dd) : d_ptr(&dd)
330{
331 d_ptr->q_ptr = this;
332}
333
334/*!
335 Destroys the QAbstractFileEngine.
336 */
337QAbstractFileEngine::~QAbstractFileEngine()
338{
339}
340
341/*!
342 \fn bool QAbstractFileEngine::open(QIODevice::OpenMode mode)
343
344 Opens the file in the specified \a mode. Returns \c true if the file
345 was successfully opened; otherwise returns \c false.
346
347 The \a mode is an OR combination of QIODevice::OpenMode and
348 QIODevice::HandlingMode values.
349
350 If the file is created as a result of this call, its permissions are
351 set according to \a permissision. Null value means an implementation-
352 specific default.
353*/
354bool QAbstractFileEngine::open(QIODevice::OpenMode openMode,
355 std::optional<QFile::Permissions> permissions)
356{
357 Q_UNUSED(openMode);
358 Q_UNUSED(permissions);
359 return false;
360}
361
362/*!
363 Closes the file, returning true if successful; otherwise returns \c false.
364
365 The default implementation always returns \c false.
366*/
367bool QAbstractFileEngine::close()
368{
369 return false;
370}
371
372/*!
373 \since 5.1
374
375 Flushes and syncs the file to disk.
376
377 Returns \c true if successful; otherwise returns \c false.
378 The default implementation always returns \c false.
379*/
380bool QAbstractFileEngine::syncToDisk()
381{
382 return false;
383}
384
385/*!
386 Flushes the open file, returning true if successful; otherwise returns
387 false.
388
389 The default implementation always returns \c false.
390*/
391bool QAbstractFileEngine::flush()
392{
393 return false;
394}
395
396/*!
397 Returns the size of the file.
398*/
399qint64 QAbstractFileEngine::size() const
400{
401 return 0;
402}
403
404/*!
405 Returns the current file position.
406
407 This is the position of the data read/write head of the file.
408*/
409qint64 QAbstractFileEngine::pos() const
410{
411 return 0;
412}
413
414/*!
415 \fn bool QAbstractFileEngine::seek(qint64 offset)
416
417 Sets the file position to the given \a offset. Returns \c true if
418 the position was successfully set; otherwise returns \c false.
419
420 The offset is from the beginning of the file, unless the
421 file is sequential.
422
423 \sa isSequential()
424*/
425bool QAbstractFileEngine::seek(qint64 pos)
426{
427 Q_UNUSED(pos);
428 return false;
429}
430
431/*!
432 Returns \c true if the file is a sequential access device; returns
433 false if the file is a direct access device.
434
435 Operations involving size() and seek(qint64) are not valid on
436 sequential devices.
437*/
438bool QAbstractFileEngine::isSequential() const
439{
440 return false;
441}
442
443/*!
444 Requests that the file is deleted from the file system. If the
445 operation succeeds return true; otherwise return false.
446
447 \sa setFileName(), rmdir()
448 */
449bool QAbstractFileEngine::remove()
450{
451 return false;
452}
453
454/*!
455 Copies the contents of this file to a file with the name \a newName.
456 Returns \c true on success; otherwise, false is returned.
457*/
458bool QAbstractFileEngine::copy(const QString &newName)
459{
460 Q_UNUSED(newName);
461 return false;
462}
463
464/*!
465 Requests that the file be renamed to \a newName in the file
466 system. If the operation succeeds return true; otherwise return
467 false.
468
469 \sa setFileName()
470 */
471bool QAbstractFileEngine::rename(const QString &newName)
472{
473 Q_UNUSED(newName);
474 return false;
475}
476
477/*!
478 \since 5.1
479
480 Requests that the file be renamed to \a newName in the file
481 system. If the new name already exists, it must be overwritten.
482 If the operation succeeds, returns \c true; otherwise returns
483 false.
484
485 \sa setFileName()
486 */
487bool QAbstractFileEngine::renameOverwrite(const QString &newName)
488{
489 Q_UNUSED(newName);
490 return false;
491}
492
493/*!
494 Creates a link from the file currently specified by fileName() to
495 \a newName. What a link is depends on the underlying filesystem
496 (be it a shortcut on Windows or a symbolic link on Unix). Returns
497 true if successful; otherwise returns \c false.
498*/
499bool QAbstractFileEngine::link(const QString &newName)
500{
501 Q_UNUSED(newName);
502 return false;
503}
504
505/*!
506 Requests that the directory \a dirName be created with the specified \a permissions.
507 If \a createParentDirectories is true, then any sub-directories in \a dirName
508 that don't exist must be created. If \a createParentDirectories is false then
509 any sub-directories in \a dirName must already exist for the function to
510 succeed. If the operation succeeds return true; otherwise return
511 false.
512
513 If \a permissions is null then implementation-specific default permissions are
514 used.
515
516 \sa setFileName(), rmdir(), isRelativePath()
517 */
518bool QAbstractFileEngine::mkdir(const QString &dirName, bool createParentDirectories,
519 std::optional<QFile::Permissions> permissions) const
520{
521 Q_UNUSED(dirName);
522 Q_UNUSED(createParentDirectories);
523 Q_UNUSED(permissions);
524 return false;
525}
526
527/*!
528 Requests that the directory \a dirName is deleted from the file
529 system. When \a recurseParentDirectories is true, then any empty
530 parent-directories in \a dirName must also be deleted. If
531 \a recurseParentDirectories is false, only the \a dirName leaf-node
532 should be deleted. In most file systems a directory cannot be deleted
533 using this function if it is non-empty. If the operation succeeds
534 return true; otherwise return false.
535
536 \sa setFileName(), remove(), mkdir(), isRelativePath()
537 */
538bool QAbstractFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
539{
540 Q_UNUSED(dirName);
541 Q_UNUSED(recurseParentDirectories);
542 return false;
543}
544
545/*!
546 Requests that the file be set to size \a size. If \a size is larger
547 than the current file then it is filled with 0's, if smaller it is
548 simply truncated. If the operations succceeds return true; otherwise
549 return false;
550
551 \sa size()
552*/
553bool QAbstractFileEngine::setSize(qint64 size)
554{
555 Q_UNUSED(size);
556 return false;
557}
558
559/*!
560 Should return true if the underlying file system is case-sensitive;
561 otherwise return false.
562 */
563bool QAbstractFileEngine::caseSensitive() const
564{
565 return false;
566}
567
568/*!
569 Return true if the file referred to by this file engine has a
570 relative path; otherwise return false.
571
572 \sa setFileName()
573 */
574bool QAbstractFileEngine::isRelativePath() const
575{
576 return false;
577}
578
579/*!
580 Requests that a list of all the files matching the \a filters
581 list based on the \a filterNames in the file engine's directory
582 are returned.
583
584 Should return an empty list if the file engine refers to a file
585 rather than a directory, or if the directory is unreadable or does
586 not exist or if nothing matches the specifications.
587
588 \sa setFileName()
589 */
590QStringList QAbstractFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
591{
592 QStringList ret;
593 QDirIterator it(fileName(), filterNames, filters);
594 while (it.hasNext()) {
595 it.next();
596 ret << it.fileName();
597 }
598 return ret;
599}
600
601/*!
602 This function should return the set of OR'd flags that are true
603 for the file engine's file, and that are in the \a type's OR'd
604 members.
605
606 In your reimplementation you can use the \a type argument as an
607 optimization hint and only return the OR'd set of members that are
608 true and that match those in \a type; in other words you can
609 ignore any members not mentioned in \a type, thus avoiding some
610 potentially expensive lookups or system calls.
611
612 \sa setFileName()
613*/
614QAbstractFileEngine::FileFlags QAbstractFileEngine::fileFlags(FileFlags type) const
615{
616 Q_UNUSED(type);
617 return {};
618}
619
620/*!
621 Requests that the file's permissions be set to \a perms. The argument
622 perms will be set to the OR-ed together combination of
623 QAbstractFileEngine::FileInfo, with only the QAbstractFileEngine::PermsMask being
624 honored. If the operations succceeds return true; otherwise return
625 false;
626
627 \sa size()
628*/
629bool QAbstractFileEngine::setPermissions(uint perms)
630{
631 Q_UNUSED(perms);
632 return false;
633}
634
635/*!
636 \since 5.9
637
638 Return an identifier that (hopefully) uniquely identifies this file in the
639 system. Returns an invalid QByteArray() if that cannot be calculated.
640*/
641QByteArray QAbstractFileEngine::id() const
642{
643 return QByteArray();
644}
645
646/*!
647 Return the file engine's current file name in the format
648 specified by \a file.
649
650 If you don't handle some \c FileName possibilities, return the
651 file name set in setFileName() when an unhandled format is
652 requested.
653
654 \sa setFileName(), FileName
655 */
656QString QAbstractFileEngine::fileName(FileName file) const
657{
658 Q_UNUSED(file);
659 return QString();
660}
661
662/*!
663 If \a owner is \c OwnerUser return the ID of the user who owns
664 the file. If \a owner is \c OwnerGroup return the ID of the group
665 that own the file. If you can't determine the owner return -2.
666
667 \sa owner(), setFileName(), FileOwner
668 */
669uint QAbstractFileEngine::ownerId(FileOwner owner) const
670{
671 Q_UNUSED(owner);
672 return 0;
673}
674
675/*!
676 If \a owner is \c OwnerUser return the name of the user who owns
677 the file. If \a owner is \c OwnerGroup return the name of the group
678 that own the file. If you can't determine the owner return
679 QString().
680
681 \sa ownerId(), setFileName(), FileOwner
682 */
683QString QAbstractFileEngine::owner(FileOwner owner) const
684{
685 Q_UNUSED(owner);
686 return QString();
687}
688
689
690/*!
691 \since 5.10
692
693 Sets the file \a time to \a newDate, returning true if successful;
694 otherwise returns false.
695
696 \sa fileTime()
697*/
698bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
699{
700 Q_UNUSED(newDate);
701 Q_UNUSED(time);
702 return false;
703}
704
705/*!
706 If \a time is \c BirthTime, return when the file was born (created). If \a
707 time is \c MetadataChangeTime, return when the file's metadata was last
708 changed. If \a time is \c ModificationTime, return when the file was most
709 recently modified. If \a time is \c AccessTime, return when the file was
710 most recently accessed (e.g. read or written). If the time cannot be
711 determined return QDateTime() (an invalid date time).
712
713 \sa setFileName(), QDateTime, QDateTime::isValid(), FileTime
714 */
715QDateTime QAbstractFileEngine::fileTime(FileTime time) const
716{
717 Q_UNUSED(time);
718 return QDateTime();
719}
720
721/*!
722 Sets the file engine's file name to \a file. This file name is the
723 file that the rest of the virtual functions will operate on.
724
725 \sa rename()
726 */
727void QAbstractFileEngine::setFileName(const QString &file)
728{
729 Q_UNUSED(file);
730}
731
732/*!
733 Returns the native file handle for this file engine. This handle must be
734 used with care; its value and type are platform specific, and using it
735 will most likely lead to non-portable code.
736*/
737int QAbstractFileEngine::handle() const
738{
739 return -1;
740}
741
742/*!
743 \since 4.3
744
745 Returns \c true if the current position is at the end of the file; otherwise,
746 returns \c false.
747
748 This function bases its behavior on calling extension() with
749 AtEndExtension. If the engine does not support this extension, false is
750 returned.
751
752 \sa extension(), supportsExtension(), QFile::atEnd()
753*/
754bool QAbstractFileEngine::atEnd() const
755{
756 return const_cast<QAbstractFileEngine *>(this)->extension(extension: AtEndExtension);
757}
758
759/*!
760 \since 4.4
761
762 Maps \a size bytes of the file into memory starting at \a offset.
763 Returns a pointer to the memory if successful; otherwise returns \c false
764 if, for example, an error occurs.
765
766 This function bases its behavior on calling extension() with
767 MapExtensionOption. If the engine does not support this extension, 0 is
768 returned.
769
770 \a flags is currently not used, but could be used in the future.
771
772 \sa unmap(), supportsExtension()
773 */
774
775uchar *QAbstractFileEngine::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
776{
777 MapExtensionOption option;
778 option.offset = offset;
779 option.size = size;
780 option.flags = flags;
781 MapExtensionReturn r;
782 if (!extension(extension: MapExtension, option: &option, output: &r))
783 return nullptr;
784 return r.address;
785}
786
787/*!
788 \since 4.4
789
790 Unmaps the memory \a address. Returns \c true if the unmap succeeds; otherwise
791 returns \c false.
792
793 This function bases its behavior on calling extension() with
794 UnMapExtensionOption. If the engine does not support this extension, false is
795 returned.
796
797 \sa map(), supportsExtension()
798 */
799bool QAbstractFileEngine::unmap(uchar *address)
800{
801 UnMapExtensionOption options;
802 options.address = address;
803 return extension(extension: UnMapExtension, option: &options);
804}
805
806/*!
807 \since 5.10
808
809 Duplicates the contents of this file (starting from the current position)
810 to the file specified by the engine \a target.
811
812 Returns \c true on success; otherwise, \c false is returned.
813 */
814bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
815{
816 Q_UNUSED(target);
817 return false;
818}
819
820/*!
821 \since 4.3
822 \class QAbstractFileEngineIterator
823 \inmodule QtCore
824 \brief The QAbstractFileEngineIterator class provides an iterator
825 interface for custom file engines.
826 \internal
827
828 If all you want is to iterate over entries in a directory, see
829 QDirIterator instead. This class is only for custom file engine authors.
830
831 QAbstractFileEngineIterator is a unidirectional single-use virtual
832 iterator that plugs into QDirIterator, providing transparent proxy
833 iteration for custom file engines.
834
835 You can subclass QAbstractFileEngineIterator to provide an iterator when
836 writing your own file engine. To plug the iterator into your file system,
837 you simply return an instance of this subclass from a reimplementation of
838 QAbstractFileEngine::beginEntryList().
839
840 Example:
841
842 \snippet code/src_corelib_io_qabstractfileengine.cpp 2
843
844 QAbstractFileEngineIterator is associated with a path, name filters, and
845 entry filters. The path is the directory that the iterator lists entries
846 in. The name filters and entry filters are provided for file engines that
847 can optimize directory listing at the iterator level (e.g., network file
848 systems that need to minimize network traffic), but they can also be
849 ignored by the iterator subclass; QAbstractFileEngineIterator already
850 provides the required filtering logics in the matchesFilters() function.
851 You can call dirName() to get the directory name, nameFilters() to get a
852 stringlist of name filters, and filters() to get the entry filters.
853
854 The pure virtual function hasNext() returns \c true if the current directory
855 has at least one more entry (i.e., the directory name is valid and
856 accessible, and we have not reached the end of the entry list), and false
857 otherwise. Reimplement next() to seek to the next entry.
858
859 The pure virtual function currentFileName() returns the name of the
860 current entry without advancing the iterator. The currentFilePath()
861 function is provided for convenience; it returns the full path of the
862 current entry.
863
864 Here is an example of how to implement an iterator that returns each of
865 three fixed entries in sequence.
866
867 \snippet code/src_corelib_io_qabstractfileengine.cpp 3
868
869 Note: QAbstractFileEngineIterator does not deal with QDir::IteratorFlags;
870 it simply returns entries for a single directory.
871
872 \sa QDirIterator
873*/
874
875/*!
876 \enum QAbstractFileEngineIterator::EntryInfoType
877 \internal
878
879 This enum describes the different types of information that can be
880 requested through the QAbstractFileEngineIterator::entryInfo() function.
881*/
882
883/*!
884 \typedef QAbstractFileEngine::Iterator
885 \since 4.3
886
887 Synonym for QAbstractFileEngineIterator.
888*/
889
890class QAbstractFileEngineIteratorPrivate
891{
892public:
893 QString path;
894 QDir::Filters filters;
895 QStringList nameFilters;
896 QFileInfo fileInfo;
897};
898
899/*!
900 Constructs a QAbstractFileEngineIterator, using the entry filters \a
901 filters, and wildcard name filters \a nameFilters.
902*/
903QAbstractFileEngineIterator::QAbstractFileEngineIterator(QDir::Filters filters,
904 const QStringList &nameFilters)
905 : d(new QAbstractFileEngineIteratorPrivate)
906{
907 d->nameFilters = nameFilters;
908 d->filters = filters;
909}
910
911/*!
912 Destroys the QAbstractFileEngineIterator.
913
914 \sa QDirIterator
915*/
916QAbstractFileEngineIterator::~QAbstractFileEngineIterator()
917{
918}
919
920/*!
921 Returns the path for this iterator. QDirIterator is responsible for
922 assigning this path; it cannot change during the iterator's lifetime.
923
924 \sa nameFilters(), filters()
925*/
926QString QAbstractFileEngineIterator::path() const
927{
928 return d->path;
929}
930
931/*!
932 \internal
933
934 Sets the iterator path to \a path. This function is called from within
935 QDirIterator.
936*/
937void QAbstractFileEngineIterator::setPath(const QString &path)
938{
939 d->path = path;
940}
941
942/*!
943 Returns the name filters for this iterator.
944
945 \sa QDir::nameFilters(), filters(), path()
946*/
947QStringList QAbstractFileEngineIterator::nameFilters() const
948{
949 return d->nameFilters;
950}
951
952/*!
953 Returns the entry filters for this iterator.
954
955 \sa QDir::filter(), nameFilters(), path()
956*/
957QDir::Filters QAbstractFileEngineIterator::filters() const
958{
959 return d->filters;
960}
961
962/*!
963 \fn QString QAbstractFileEngineIterator::currentFileName() const = 0
964
965 This pure virtual function returns the name of the current directory
966 entry, excluding the path.
967
968 \sa currentFilePath()
969*/
970
971/*!
972 Returns the path to the current directory entry. It's the same as
973 prepending path() to the return value of currentFileName().
974
975 \sa currentFileName()
976*/
977QString QAbstractFileEngineIterator::currentFilePath() const
978{
979 QString name = currentFileName();
980 if (!name.isNull()) {
981 QString tmp = path();
982 if (!tmp.isEmpty()) {
983 if (!tmp.endsWith(c: u'/'))
984 tmp.append(c: u'/');
985 name.prepend(s: tmp);
986 }
987 }
988 return name;
989}
990
991/*!
992 The virtual function returns a QFileInfo for the current directory
993 entry. This function is provided for convenience. It can also be slightly
994 faster than creating a QFileInfo object yourself, as the object returned
995 by this function might contain cached information that QFileInfo otherwise
996 would have to access through the file engine.
997
998 \sa currentFileName()
999*/
1000QFileInfo QAbstractFileEngineIterator::currentFileInfo() const
1001{
1002 QString path = currentFilePath();
1003 if (d->fileInfo.filePath() != path)
1004 d->fileInfo.setFile(path);
1005
1006 // return a shallow copy
1007 return d->fileInfo;
1008}
1009
1010/*!
1011 \internal
1012
1013 Returns the entry info \a type for this iterator's current directory entry
1014 as a QVariant. If \a type is undefined for this entry, a null QVariant is
1015 returned.
1016
1017 \sa QAbstractFileEngine::beginEntryList(), QDir::beginEntryList()
1018*/
1019QVariant QAbstractFileEngineIterator::entryInfo(EntryInfoType type) const
1020{
1021 Q_UNUSED(type);
1022 return QVariant();
1023}
1024
1025/*!
1026 \fn virtual QString QAbstractFileEngineIterator::next() = 0
1027
1028 This pure virtual function advances the iterator to the next directory
1029 entry, and returns the file path to the current entry.
1030
1031 This function can optionally make use of nameFilters() and filters() to
1032 optimize its performance.
1033
1034 Reimplement this function in a subclass to advance the iterator.
1035
1036 \sa QDirIterator::next()
1037*/
1038
1039/*!
1040 \fn virtual bool QAbstractFileEngineIterator::hasNext() const = 0
1041
1042 This pure virtual function returns \c true if there is at least one more
1043 entry in the current directory (i.e., the iterator path is valid and
1044 accessible, and the iterator has not reached the end of the entry list).
1045
1046 \sa QDirIterator::hasNext()
1047*/
1048
1049/*!
1050 Returns an instance of a QAbstractFileEngineIterator using \a filters for
1051 entry filtering and \a filterNames for name filtering. This function is
1052 called by QDirIterator to initiate directory iteration.
1053
1054 QDirIterator takes ownership of the returned instance, and deletes it when
1055 it's done.
1056
1057 \sa QDirIterator
1058*/
1059QAbstractFileEngine::Iterator *QAbstractFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
1060{
1061 Q_UNUSED(filters);
1062 Q_UNUSED(filterNames);
1063 return nullptr;
1064}
1065
1066/*!
1067 \internal
1068*/
1069QAbstractFileEngine::Iterator *QAbstractFileEngine::endEntryList()
1070{
1071 return nullptr;
1072}
1073
1074/*!
1075 Reads a number of characters from the file into \a data. At most
1076 \a maxlen characters will be read.
1077
1078 Returns -1 if a fatal error occurs, or 0 if there are no bytes to
1079 read.
1080*/
1081qint64 QAbstractFileEngine::read(char *data, qint64 maxlen)
1082{
1083 Q_UNUSED(data);
1084 Q_UNUSED(maxlen);
1085 return -1;
1086}
1087
1088/*!
1089 Writes \a len bytes from \a data to the file. Returns the number
1090 of characters written on success; otherwise returns -1.
1091*/
1092qint64 QAbstractFileEngine::write(const char *data, qint64 len)
1093{
1094 Q_UNUSED(data);
1095 Q_UNUSED(len);
1096 return -1;
1097}
1098
1099/*!
1100 This function reads one line, terminated by a '\\n' character, from the
1101 file info \a data. At most \a maxlen characters will be read. The
1102 end-of-line character is included.
1103*/
1104qint64 QAbstractFileEngine::readLine(char *data, qint64 maxlen)
1105{
1106 qint64 readSoFar = 0;
1107 while (readSoFar < maxlen) {
1108 char c;
1109 qint64 readResult = read(data: &c, maxlen: 1);
1110 if (readResult <= 0)
1111 return (readSoFar > 0) ? readSoFar : -1;
1112 ++readSoFar;
1113 *data++ = c;
1114 if (c == '\n')
1115 return readSoFar;
1116 }
1117 return readSoFar;
1118}
1119
1120/*!
1121 \enum QAbstractFileEngine::Extension
1122 \since 4.3
1123
1124 This enum describes the types of extensions that the file engine can
1125 support. Before using these extensions, you must verify that the extension
1126 is supported (i.e., call supportsExtension()).
1127
1128 \value AtEndExtension Whether the current file position is at the end of
1129 the file or not. This extension allows file engines that implement local
1130 buffering to report end-of-file status without having to check the size of
1131 the file. It is also useful for sequential files, where the size of the
1132 file cannot be used to determine whether or not you have reached the end.
1133 This extension returns \c true if the file is at the end; otherwise it returns
1134 false. The input and output arguments to extension() are ignored.
1135
1136 \value FastReadLineExtension Whether the file engine provides a
1137 fast implementation for readLine() or not. If readLine() remains
1138 unimplemented in the file engine, QAbstractFileEngine will provide
1139 an implementation based on calling read() repeatedly. If
1140 supportsExtension() returns \c false for this extension, however,
1141 QIODevice can provide a faster implementation by making use of its
1142 internal buffer. For engines that already provide a fast readLine()
1143 implementation, returning false for this extension can avoid
1144 unnecessary double-buffering in QIODevice.
1145
1146 \value MapExtension Whether the file engine provides the ability to map
1147 a file to memory.
1148
1149 \value UnMapExtension Whether the file engine provides the ability to
1150 unmap memory that was previously mapped.
1151*/
1152
1153/*!
1154 \class QAbstractFileEngine::ExtensionOption
1155 \inmodule QtCore
1156 \since 4.3
1157 \brief provides an extended input argument to QAbstractFileEngine's
1158 extension support.
1159
1160 \sa QAbstractFileEngine::extension()
1161*/
1162
1163/*!
1164 \class QAbstractFileEngine::ExtensionReturn
1165 \inmodule QtCore
1166 \since 4.3
1167 \brief provides an extended output argument to QAbstractFileEngine's
1168 extension support.
1169
1170 \sa QAbstractFileEngine::extension()
1171*/
1172
1173/*!
1174 \since 4.3
1175
1176 This virtual function can be reimplemented in a QAbstractFileEngine
1177 subclass to provide support for extensions. The \a option argument is
1178 provided as input to the extension, and this function can store output
1179 results in \a output.
1180
1181 The behavior of this function is determined by \a extension; see the
1182 Extension documentation for details.
1183
1184 You can call supportsExtension() to check if an extension is supported by
1185 the file engine.
1186
1187 By default, no extensions are supported, and this function returns \c false.
1188
1189 \sa supportsExtension(), Extension
1190*/
1191bool QAbstractFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
1192{
1193 Q_UNUSED(extension);
1194 Q_UNUSED(option);
1195 Q_UNUSED(output);
1196 return false;
1197}
1198
1199/*!
1200 \since 4.3
1201
1202 This virtual function returns \c true if the file engine supports \a
1203 extension; otherwise, false is returned. By default, no extensions are
1204 supported.
1205
1206 \sa extension()
1207*/
1208bool QAbstractFileEngine::supportsExtension(Extension extension) const
1209{
1210 Q_UNUSED(extension);
1211 return false;
1212}
1213
1214/*!
1215 Returns the QFile::FileError that resulted from the last failed
1216 operation. If QFile::UnspecifiedError is returned, QFile will
1217 use its own idea of the error status.
1218
1219 \sa QFile::FileError, errorString()
1220 */
1221QFile::FileError QAbstractFileEngine::error() const
1222{
1223 Q_D(const QAbstractFileEngine);
1224 return d->fileError;
1225}
1226
1227/*!
1228 Returns the human-readable message appropriate to the current error
1229 reported by error(). If no suitable string is available, an
1230 empty string is returned.
1231
1232 \sa error()
1233 */
1234QString QAbstractFileEngine::errorString() const
1235{
1236 Q_D(const QAbstractFileEngine);
1237 return d->errorString;
1238}
1239
1240/*!
1241 Sets the error type to \a error, and the error string to \a errorString.
1242 Call this function to set the error values returned by the higher-level
1243 classes.
1244
1245 \sa QFile::error(), QIODevice::errorString(), QIODevice::setErrorString()
1246*/
1247void QAbstractFileEngine::setError(QFile::FileError error, const QString &errorString)
1248{
1249 Q_D(QAbstractFileEngine);
1250 d->fileError = error;
1251 d->errorString = errorString;
1252}
1253
1254QT_END_NAMESPACE
1255

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