File indexing completed on 2024-05-12 03:54:55
0001 /* 0002 This software is a contribution of the LiMux project of the city of Munich. 0003 SPDX-FileCopyrightText: 2021 Robert Hoffmann <robert@roberthoffmann.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "knetworkmounts.h" 0009 #include "knetworkmounts_p.h" 0010 0011 #include <QCoreApplication> 0012 #include <QGlobalStatic> 0013 0014 #include <QDebug> 0015 #include <QDir> 0016 #include <QStandardPaths> 0017 0018 KNetworkMountsPrivate::KNetworkMountsPrivate(KNetworkMounts *qq) 0019 : q(qq) 0020 { 0021 } 0022 0023 KNetworkMounts *KNetworkMounts::self() 0024 { 0025 static KNetworkMounts s_self; 0026 return &s_self; 0027 } 0028 0029 KNetworkMounts::KNetworkMounts() 0030 : d(new KNetworkMountsPrivate(this)) 0031 { 0032 const QString configFileName = QStringLiteral("%1/network_mounts").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)); 0033 d->m_settings = new QSettings(configFileName, QSettings::Format::IniFormat, this); 0034 0035 for (const auto type : {KNetworkMounts::NfsPaths, KNetworkMounts::SmbPaths, KNetworkMounts::SymlinkDirectory, KNetworkMounts::SymlinkToNetworkMount}) { 0036 QString typeStr = enumToString(type); 0037 QStringList slowPaths = d->m_settings->value(typeStr, QStringList()).toStringList(); 0038 0039 if (ensureTrailingSlashes(&slowPaths)) { 0040 d->m_settings->setValue(typeStr, slowPaths); 0041 } 0042 } 0043 } 0044 0045 KNetworkMounts::~KNetworkMounts() 0046 { 0047 } 0048 0049 bool KNetworkMounts::isSlowPath(const QString &path, KNetworkMountsType type) 0050 { 0051 return !getMatchingPath(path, paths(type)).isEmpty(); 0052 } 0053 0054 bool KNetworkMounts::isOptionEnabledForPath(const QString &path, KNetworkMountOption option) 0055 { 0056 if (!isEnabled()) { 0057 return false; 0058 } 0059 0060 if (!isSlowPath(path)) { 0061 return false; 0062 } 0063 0064 return isOptionEnabled(option, true); 0065 } 0066 0067 bool KNetworkMounts::isEnabled() const 0068 { 0069 return d->m_settings->value(QStringLiteral("EnableOptimizations"), false).toBool(); 0070 } 0071 0072 void KNetworkMounts::setEnabled(const bool value) 0073 { 0074 d->m_settings->setValue(QStringLiteral("EnableOptimizations"), value); 0075 } 0076 0077 bool KNetworkMounts::isOptionEnabled(const KNetworkMountOption option, const bool defaultValue) const 0078 { 0079 return d->m_settings->value(enumToString(option), defaultValue).toBool(); 0080 } 0081 0082 void KNetworkMounts::setOption(const KNetworkMountOption option, const bool value) 0083 { 0084 d->m_settings->setValue(enumToString(option), value); 0085 } 0086 0087 QStringList KNetworkMounts::paths(KNetworkMountsType type) const 0088 { 0089 if (type == Any) { 0090 QStringList paths; 0091 paths.reserve(4); 0092 for (const auto networkMountType : 0093 {KNetworkMounts::NfsPaths, KNetworkMounts::SmbPaths, KNetworkMounts::SymlinkDirectory, KNetworkMounts::SymlinkToNetworkMount}) { 0094 paths.append(d->m_settings->value(enumToString(networkMountType), QStringList()).toStringList()); 0095 } 0096 return paths; 0097 } else { 0098 return d->m_settings->value(enumToString(type), QStringList()).toStringList(); 0099 } 0100 } 0101 0102 void KNetworkMounts::setPaths(const QStringList &paths, KNetworkMountsType type) 0103 { 0104 QStringList _paths(paths); 0105 ensureTrailingSlashes(&_paths); 0106 d->m_settings->setValue(enumToString(type), _paths); 0107 } 0108 0109 void KNetworkMounts::addPath(const QString &path, KNetworkMountsType type) 0110 { 0111 QString _path(path); 0112 ensureTrailingSlash(&_path); 0113 QStringList newPaths = paths(type); 0114 newPaths.append(_path); 0115 d->m_settings->setValue(enumToString(type), newPaths); 0116 } 0117 0118 typedef QHash<QString /*symlink*/, QString /*canonical path*/> symlinkCanonicalPathHash; 0119 Q_GLOBAL_STATIC(symlinkCanonicalPathHash, s_canonicalLinkSpacePaths) 0120 0121 QString KNetworkMounts::canonicalSymlinkPath(const QString &path) 0122 { 0123 bool useCache = isOptionEnabled(KNetworkMountOption::SymlinkPathsUseCache, true); 0124 if (useCache) { 0125 const QString resolved = s_canonicalLinkSpacePaths->value(path); 0126 0127 if (!resolved.isEmpty()) { 0128 return resolved; 0129 } 0130 } 0131 0132 QString symlinkPath = getMatchingPath(path, paths(KNetworkMountsType::SymlinkToNetworkMount)); 0133 if (!symlinkPath.isEmpty()) { 0134 // remove trailing slash 0135 symlinkPath.chop(1); 0136 0137 QFileInfo link(symlinkPath); 0138 QString linkPath(path); 0139 QString target = link.symLinkTarget(); 0140 0141 if (target.isEmpty()) { 0142 // not a symlink 0143 if (useCache) { 0144 s_canonicalLinkSpacePaths->insert(path, path); 0145 } 0146 return path; 0147 } else { 0148 // symlink 0149 // replace only the first occurence of symlinkPath in linkPath with the link target 0150 // linkPath.startsWith(symlinkPath) because of getMatchingPath 0151 linkPath.replace(0, symlinkPath.size(), target); 0152 0153 if (useCache) { 0154 s_canonicalLinkSpacePaths->insert(path, linkPath); 0155 } 0156 return linkPath; 0157 } 0158 } 0159 0160 QString linkSpacePath = getMatchingPath(path, paths(KNetworkMountsType::SymlinkDirectory)); 0161 if (!linkSpacePath.isEmpty()) { 0162 QString _path = path; 0163 if (!_path.endsWith(QLatin1Char('/'))) { 0164 _path.append(QLatin1Char('/')); 0165 } 0166 0167 if (_path == linkSpacePath) { 0168 if (useCache) { 0169 s_canonicalLinkSpacePaths->insert(path, path); 0170 } 0171 return path; 0172 } 0173 0174 // search for symlink, linkSpacePath always ends with '/' 0175 int linkIndex = path.indexOf(QLatin1Char('/'), linkSpacePath.length()); 0176 const QString symlink = path.left(linkIndex); 0177 0178 if (useCache && s_canonicalLinkSpacePaths->contains(symlink)) { 0179 QString linkPath(path); 0180 // replace only the first occurence of symlink in linkPath 0181 linkPath.replace(0, symlink.size(), s_canonicalLinkSpacePaths->value(symlink)); 0182 s_canonicalLinkSpacePaths->insert(path, linkPath); 0183 return linkPath; 0184 } else { 0185 QFileInfo link(symlink); 0186 0187 if (link.isSymLink()) { 0188 QString linkPath(path); 0189 // replace only the first occurence of symlink in linkPath 0190 linkPath.replace(0, symlink.size(), link.symLinkTarget()); 0191 0192 if (useCache) { 0193 s_canonicalLinkSpacePaths->insert(path, linkPath); 0194 } 0195 return linkPath; 0196 } else { 0197 if (useCache) { 0198 s_canonicalLinkSpacePaths->insert(path, path); 0199 } 0200 } 0201 } 0202 } 0203 0204 return path; 0205 } 0206 0207 void KNetworkMounts::clearCache() 0208 { 0209 if (s_canonicalLinkSpacePaths.exists()) { 0210 s_canonicalLinkSpacePaths->clear(); 0211 } 0212 } 0213 0214 void KNetworkMounts::sync() 0215 { 0216 d->m_settings->sync(); 0217 } 0218 0219 #include "moc_knetworkmounts.cpp"