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