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