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
qfilesystemengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <QtCore/qdir.h>
6#include <QtCore/qset.h>
7#include <QtCore/qstringbuilder.h>
8#include <QtCore/private/qabstractfileengine_p.h>
9#ifdef QT_BUILD_CORE_LIB
10#include <QtCore/private/qresource_p.h>
11#endif
12#include <QtCore/private/qduplicatetracker_p.h>
13
15
16/*! \class QFileSystemEngine
17 \internal
18
19 QFileSystemEngine offers OS-independent API for native system library
20 methods, which work with files on physical disk drives; using such methods
21 directly is faster than using a custom file engine (see QAbstractFileEngine
22 and its sub-classes). Typically, you need a custom file engine when working
23 with virtual file systems (for example QResource). Various Qt classes,
24 for example QDir, QFile, and QFileInfo, can handle both types of files by
25 detecting the file path scheme, for example, \c file:///, \c :/someresource
26 (QResource).
27
28 \sa QAbstractFileEngine, QAbstractFileEngineHandler, QFSFileEngine, QResourceFileEngine
29*/
30
31/*!
32 \internal
33
34 Returns the canonicalized form of \a path (i.e., with all symlinks
35 resolved, and all redundant path elements removed.
36*/
37QString QFileSystemEngine::slowCanonicalized(const QString &path)
38{
39 if (path.isEmpty())
40 return path;
41
42 QFileInfo fi;
43 const QChar slash(u'/');
44 QString tmpPath = path;
45 qsizetype separatorPos = 0;
46 QSet<QString> nonSymlinks;
47 QDuplicateTracker<QString> known;
48
49 (void)known.hasSeen(path);
50 do {
51#ifdef Q_OS_WIN
52 if (separatorPos == 0) {
53 if (tmpPath.size() >= 2 && tmpPath.at(0) == slash && tmpPath.at(1) == slash) {
54 // UNC, skip past the first two elements
55 separatorPos = tmpPath.indexOf(slash, 2);
56 } else if (tmpPath.size() >= 3 && tmpPath.at(1) == u':' && tmpPath.at(2) == slash) {
57 // volume root, skip since it can not be a symlink
58 separatorPos = 2;
59 }
60 }
61 if (separatorPos != -1)
62#endif
63 separatorPos = tmpPath.indexOf(slash, separatorPos + 1);
64 QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos);
65 if (!nonSymlinks.contains(prefix)) {
66 fi.setFile(prefix);
67 if (fi.isSymLink()) {
68 QString target = fi.symLinkTarget();
69 if (separatorPos != -1) {
70 if (fi.isDir() && !target.endsWith(slash))
71 target.append(slash);
72 target.append(QStringView{tmpPath}.mid(separatorPos));
73 }
74 tmpPath = QDir::cleanPath(target);
75 separatorPos = 0;
76
77 if (known.hasSeen(tmpPath))
78 return QString();
79 } else {
80 nonSymlinks.insert(prefix);
81 }
82 }
83 } while (separatorPos != -1);
84
85 return QDir::cleanPath(tmpPath);
86}
87
88static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry)
89{
90 if (resolvingEntry) {
91 if (!QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute)
92 || !data.exists()) {
93 data.clear();
94 return false;
95 }
96 }
97
98 return true;
99}
100
101static inline bool _q_checkEntry(std::unique_ptr<QAbstractFileEngine> &engine, bool resolvingEntry)
102{
103 if (resolvingEntry) {
104 if (!(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) {
105 engine.reset();
106 return false;
107 }
108 }
109
110 return true;
111}
112
113static bool _q_createLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
114 std::unique_ptr<QAbstractFileEngine> &engine,
115 bool resolvingEntry = false)
116{
117 QString const &filePath = entry.filePath();
118 if ((engine = qt_custom_file_engine_handler_create(filePath)))
119 return _q_checkEntry(engine, resolvingEntry);
120
121#if defined(QT_BUILD_CORE_LIB)
122 for (qsizetype prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
123 QChar const ch = filePath[prefixSeparator];
124 if (ch == u'/')
125 break;
126
127 if (ch == u':') {
128 if (prefixSeparator == 0) {
129 engine = std::make_unique<QResourceFileEngine>(filePath);
130 return _q_checkEntry(engine, resolvingEntry);
131 }
132
133 if (prefixSeparator == 1)
134 break;
135
136 const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator));
137 for (int i = 0; i < paths.size(); i++) {
138 entry = QFileSystemEntry(QDir::cleanPath(
139 paths.at(i) % u'/' % QStringView{filePath}.mid(prefixSeparator + 1)));
140 // Recurse!
141 if (_q_createLegacyEngine_recursive(entry, data, engine, true))
142 return true;
143 }
144
145 // entry may have been clobbered at this point.
146 return false;
147 }
148
149 // There's no need to fully validate the prefix here. Consulting the
150 // unicode tables could be expensive and validation is already
151 // performed in QDir::setSearchPaths.
152 //
153 // if (!ch.isLetterOrNumber())
154 // break;
155 }
156#endif // defined(QT_BUILD_CORE_LIB)
157
158 return _q_checkEntry(entry, data, resolvingEntry);
159}
160
161Q_CORE_EXPORT bool qt_isCaseSensitive(const QFileSystemEntry &entry, QFileSystemMetaData &data)
162{
163 // called from QtGui (QFileSystemModel, QFileInfoGatherer)
164 return QFileSystemEngine::isCaseSensitive(entry, data);
165}
166
167/*!
168 \internal
169
170 Resolves the \a entry (see QDir::searchPaths) and returns an engine for
171 it, but never a QFSFileEngine.
172
173 Returns a file engine that can be used to access the entry. Returns 0 if
174 QFileSystemEngine API should be used to query and interact with the file
175 system object.
176*/
177std::unique_ptr<QAbstractFileEngine>
178QFileSystemEngine::createLegacyEngine(QFileSystemEntry &entry, QFileSystemMetaData &data)
179{
180 QFileSystemEntry copy = entry;
181 std::unique_ptr<QAbstractFileEngine> engine;
182
183 if (_q_createLegacyEngine_recursive(copy, data, engine))
184 // Reset entry to resolved copy.
185 entry = copy;
186 else
187 data.clear();
188
189 return engine;
190}
191
192//static
193QString QFileSystemEngine::resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
194{
195#if defined(Q_OS_WIN)
196 Q_UNUSED(metaData);
197 return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerUser);
198#else //(Q_OS_UNIX)
199 if (!metaData.hasFlags(QFileSystemMetaData::UserId))
200 QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::UserId);
201 if (!metaData.exists())
202 return QString();
203 return resolveUserName(metaData.userId());
204#endif
205}
206
207//static
208QString QFileSystemEngine::resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
209{
210#if defined(Q_OS_WIN)
211 Q_UNUSED(metaData);
212 return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerGroup);
213#else //(Q_OS_UNIX)
214 if (!metaData.hasFlags(QFileSystemMetaData::GroupId))
215 QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::GroupId);
216 if (!metaData.exists())
217 return QString();
218 return resolveGroupName(metaData.groupId());
219#endif
220}
221
222//static
223QFileSystemEntry QFileSystemEngine::getJunctionTarget(const QFileSystemEntry &link,
224 QFileSystemMetaData &data)
225{
226#if defined(Q_OS_WIN)
227 return junctionTarget(link, data);
228#else
229 Q_UNUSED(link);
230 Q_UNUSED(data);
231 return {};
232#endif
233}
234
235QT_END_NAMESPACE
Combined button and popup list for selecting options.
static bool _q_createLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data, std::unique_ptr< QAbstractFileEngine > &engine, bool resolvingEntry=false)
static bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry)
static bool _q_checkEntry(std::unique_ptr< QAbstractFileEngine > &engine, bool resolvingEntry)
Q_CORE_EXPORT bool qt_isCaseSensitive(const QFileSystemEntry &entry, QFileSystemMetaData &data)