blob: 21847c2a7c8d5d5fca2370030b3337a825c18433 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qfilesystemengine_p.h"
#include <QtCore/qdir.h>
#include <QtCore/qset.h>
#include <QtCore/qstringbuilder.h>
#include <QtCore/private/qabstractfileengine_p.h>
#ifdef QT_BUILD_CORE_LIB
#include <QtCore/private/qresource_p.h>
#endif
QT_BEGIN_NAMESPACE
/*!
\internal
Returns the canonicalized form of \a path (i.e., with all symlinks
resolved, and all redundant path elements removed.
*/
QString QFileSystemEngine::slowCanonicalized(const QString &path)
{
if (path.isEmpty())
return path;
QFileInfo fi;
const QChar slash(QLatin1Char('/'));
QString tmpPath = path;
int separatorPos = 0;
QSet<QString> nonSymlinks;
QSet<QString> known;
known.insert(path);
do {
#ifdef Q_OS_WIN
if (separatorPos == 0) {
if (tmpPath.size() >= 2 && tmpPath.at(0) == slash && tmpPath.at(1) == slash) {
// UNC, skip past the first two elements
separatorPos = tmpPath.indexOf(slash, 2);
} else if (tmpPath.size() >= 3 && tmpPath.at(1) == QLatin1Char(':') && tmpPath.at(2) == slash) {
// volume root, skip since it can not be a symlink
separatorPos = 2;
}
}
if (separatorPos != -1)
#endif
separatorPos = tmpPath.indexOf(slash, separatorPos + 1);
QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos);
if (!nonSymlinks.contains(prefix)) {
fi.setFile(prefix);
if (fi.isSymLink()) {
QString target = fi.symLinkTarget();
if (separatorPos != -1) {
if (fi.isDir() && !target.endsWith(slash))
target.append(slash);
target.append(tmpPath.midRef(separatorPos));
}
tmpPath = QDir::cleanPath(target);
separatorPos = 0;
if (known.contains(tmpPath))
return QString();
known.insert(tmpPath);
} else {
nonSymlinks.insert(prefix);
}
}
} while (separatorPos != -1);
return QDir::cleanPath(tmpPath);
}
static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry)
{
if (resolvingEntry) {
if (!QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute)
|| !data.exists()) {
data.clear();
return false;
}
}
return true;
}
static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEntry)
{
if (resolvingEntry) {
if (!(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) {
delete engine;
engine = nullptr;
return false;
}
}
return true;
}
static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
QAbstractFileEngine *&engine, bool resolvingEntry = false)
{
QString const &filePath = entry.filePath();
if ((engine = qt_custom_file_engine_handler_create(filePath)))
return _q_checkEntry(engine, resolvingEntry);
#if defined(QT_BUILD_CORE_LIB)
for (int prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
QChar const ch = filePath[prefixSeparator];
if (ch == QLatin1Char('/'))
break;
if (ch == QLatin1Char(':')) {
if (prefixSeparator == 0) {
engine = new QResourceFileEngine(filePath);
return _q_checkEntry(engine, resolvingEntry);
}
if (prefixSeparator == 1)
break;
const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator));
for (int i = 0; i < paths.count(); i++) {
entry = QFileSystemEntry(QDir::cleanPath(paths.at(i) % QLatin1Char('/') % filePath.midRef(prefixSeparator + 1)));
// Recurse!
if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true))
return true;
}
// entry may have been clobbered at this point.
return false;
}
// There's no need to fully validate the prefix here. Consulting the
// unicode tables could be expensive and validation is already
// performed in QDir::setSearchPaths.
//
// if (!ch.isLetterOrNumber())
// break;
}
#endif // defined(QT_BUILD_CORE_LIB)
return _q_checkEntry(entry, data, resolvingEntry);
}
/*!
\internal
Resolves the \a entry (see QDir::searchPaths) and returns an engine for
it, but never a QFSFileEngine.
Returns a file engine that can be used to access the entry. Returns 0 if
QFileSystemEngine API should be used to query and interact with the file
system object.
*/
QAbstractFileEngine *QFileSystemEngine::resolveEntryAndCreateLegacyEngine(
QFileSystemEntry &entry, QFileSystemMetaData &data) {
QFileSystemEntry copy = entry;
QAbstractFileEngine *engine = nullptr;
if (_q_resolveEntryAndCreateLegacyEngine_recursive(copy, data, engine))
// Reset entry to resolved copy.
entry = copy;
else
data.clear();
return engine;
}
//static
QString QFileSystemEngine::resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
{
#if defined(Q_OS_WIN)
Q_UNUSED(metaData);
return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerUser);
#else //(Q_OS_UNIX)
if (!metaData.hasFlags(QFileSystemMetaData::UserId))
QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::UserId);
if (!metaData.exists())
return QString();
return resolveUserName(metaData.userId());
#endif
}
//static
QString QFileSystemEngine::resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
{
#if defined(Q_OS_WIN)
Q_UNUSED(metaData);
return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerGroup);
#else //(Q_OS_UNIX)
if (!metaData.hasFlags(QFileSystemMetaData::GroupId))
QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::GroupId);
if (!metaData.exists())
return QString();
return resolveGroupName(metaData.groupId());
#endif
}
QT_END_NAMESPACE