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 | |
20 | QT_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 | |
68 | Q_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 | */ |
74 | Q_GLOBAL_STATIC(QReadWriteLock, fileEngineHandlerMutex, QReadWriteLock::Recursive) |
75 | Q_CONSTINIT static bool qt_abstractfileenginehandlerlist_shutDown = false; |
76 | class QAbstractFileEngineHandlerList : public QList<QAbstractFileEngineHandler *> |
77 | { |
78 | public: |
79 | ~QAbstractFileEngineHandlerList() |
80 | { |
81 | QWriteLocker locker(fileEngineHandlerMutex()); |
82 | qt_abstractfileenginehandlerlist_shutDown = true; |
83 | } |
84 | }; |
85 | Q_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 | */ |
96 | QAbstractFileEngineHandler::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 | */ |
107 | QAbstractFileEngineHandler::~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 | */ |
124 | QAbstractFileEngine *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 | */ |
165 | QAbstractFileEngine *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 | */ |
319 | QAbstractFileEngine::QAbstractFileEngine() : d_ptr(new QAbstractFileEnginePrivate) |
320 | { |
321 | d_ptr->q_ptr = this; |
322 | } |
323 | |
324 | /*! |
325 | \internal |
326 | |
327 | Constructs a QAbstractFileEngine. |
328 | */ |
329 | QAbstractFileEngine::QAbstractFileEngine(QAbstractFileEnginePrivate &dd) : d_ptr(&dd) |
330 | { |
331 | d_ptr->q_ptr = this; |
332 | } |
333 | |
334 | /*! |
335 | Destroys the QAbstractFileEngine. |
336 | */ |
337 | QAbstractFileEngine::~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 | */ |
354 | bool 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 | */ |
367 | bool 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 | */ |
380 | bool 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 | */ |
391 | bool QAbstractFileEngine::flush() |
392 | { |
393 | return false; |
394 | } |
395 | |
396 | /*! |
397 | Returns the size of the file. |
398 | */ |
399 | qint64 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 | */ |
409 | qint64 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 | */ |
425 | bool 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 | */ |
438 | bool 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 | */ |
449 | bool 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 | */ |
458 | bool 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 | */ |
471 | bool 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 | */ |
487 | bool 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 | */ |
499 | bool 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 | */ |
518 | bool 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 | */ |
538 | bool 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 | */ |
553 | bool 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 | */ |
563 | bool 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 | */ |
574 | bool 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 | */ |
590 | QStringList 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 | */ |
614 | QAbstractFileEngine::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 | */ |
629 | bool 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 | */ |
641 | QByteArray 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 | */ |
656 | QString 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 | */ |
669 | uint 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 | */ |
683 | QString 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 | */ |
698 | bool 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 | */ |
715 | QDateTime 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 | */ |
727 | void 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 | */ |
737 | int 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 | */ |
754 | bool 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 | |
775 | uchar *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 | */ |
799 | bool 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 | */ |
814 | bool 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 | |
890 | class QAbstractFileEngineIteratorPrivate |
891 | { |
892 | public: |
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 | */ |
903 | QAbstractFileEngineIterator::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 | */ |
916 | QAbstractFileEngineIterator::~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 | */ |
926 | QString 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 | */ |
937 | void 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 | */ |
947 | QStringList 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 | */ |
957 | QDir::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 | */ |
977 | QString 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 | */ |
1000 | QFileInfo 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 | */ |
1019 | QVariant 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 | */ |
1059 | QAbstractFileEngine::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 | */ |
1069 | QAbstractFileEngine::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 | */ |
1081 | qint64 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 | */ |
1092 | qint64 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 | */ |
1104 | qint64 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 | */ |
1191 | bool 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 | */ |
1208 | bool 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 | */ |
1221 | QFile::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 | */ |
1234 | QString 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 | */ |
1247 | void QAbstractFileEngine::setError(QFile::FileError error, const QString &errorString) |
1248 | { |
1249 | Q_D(QAbstractFileEngine); |
1250 | d->fileError = error; |
1251 | d->errorString = errorString; |
1252 | } |
1253 | |
1254 | QT_END_NAMESPACE |
1255 | |