File indexing completed on 2024-11-10 04:40:49
0001 /* 0002 SPDX-FileCopyrightText: 2011 Volker Krause <vkrause@kde.org> 0003 SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "akonadiprivate_debug.h" 0009 #include "instance_p.h" 0010 #include "standarddirs_p.h" 0011 0012 #include <QCoreApplication> 0013 #include <QDir> 0014 #include <QFile> 0015 #include <QFileInfo> 0016 #include <QList> 0017 #include <QStandardPaths> 0018 0019 using namespace Akonadi; 0020 0021 namespace 0022 { 0023 QString buildFullRelPath(const char *resource, const QString &relPath) 0024 { 0025 QString fullRelPath = QStringLiteral("/akonadi"); 0026 #ifdef Q_OS_WIN 0027 // On Windows all Generic*Location fall into ~/AppData/Local so we need to disambiguate 0028 // inside the "akonadi" folder whether it's data or config. 0029 fullRelPath += QLatin1Char('/') + QString::fromLocal8Bit(resource); 0030 #else 0031 Q_UNUSED(resource) 0032 #endif 0033 0034 if (Akonadi::Instance::hasIdentifier()) { 0035 fullRelPath += QLatin1StringView("/instance/") + Akonadi::Instance::identifier(); 0036 } 0037 if (!relPath.isEmpty()) { 0038 fullRelPath += QLatin1Char('/') + relPath; 0039 } 0040 return fullRelPath; 0041 } 0042 0043 } // namespace 0044 0045 QString StandardDirs::configFile(const QString &configFile, FileAccessMode openMode) 0046 { 0047 const QString savePath = StandardDirs::saveDir("config") + QLatin1Char('/') + configFile; 0048 if (openMode == WriteOnly) { 0049 return savePath; 0050 } 0051 0052 auto path = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QLatin1StringView("akonadi/") + configFile); 0053 // HACK: when using instance namespaces, ignore the non-namespaced file 0054 if (Akonadi::Instance::hasIdentifier() && path.startsWith(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation))) { 0055 path.clear(); 0056 } 0057 0058 if (path.isEmpty()) { 0059 return savePath; 0060 } else if (openMode == ReadOnly || path == savePath) { 0061 return path; 0062 } 0063 0064 // file found in system paths and mode is ReadWrite, thus 0065 // we copy to the home path location and return this path 0066 QFile::copy(path, savePath); 0067 return savePath; 0068 } 0069 0070 QString StandardDirs::serverConfigFile(FileAccessMode openMode) 0071 { 0072 return configFile(QStringLiteral("akonadiserverrc"), openMode); 0073 } 0074 0075 QString StandardDirs::connectionConfigFile(FileAccessMode openMode) 0076 { 0077 return configFile(QStringLiteral("akonadiconnectionrc"), openMode); 0078 } 0079 0080 QString StandardDirs::agentsConfigFile(FileAccessMode openMode) 0081 { 0082 return configFile(QStringLiteral("agentsrc"), openMode); 0083 } 0084 0085 QString StandardDirs::agentConfigFile(const QString &identifier, FileAccessMode openMode) 0086 { 0087 return configFile(QStringLiteral("agent_config_") + identifier, openMode); 0088 } 0089 0090 QString StandardDirs::saveDir(const char *resource, const QString &relPath) 0091 { 0092 const QString fullRelPath = buildFullRelPath(resource, relPath); 0093 QString fullPath; 0094 if (qstrncmp(resource, "config", 6) == 0) { 0095 fullPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + fullRelPath; 0096 } else if (qstrncmp(resource, "data", 4) == 0) { 0097 fullPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + fullRelPath; 0098 } else if (qstrncmp(resource, "runtime", 7) == 0) { 0099 fullPath = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation) + fullRelPath; 0100 } else { 0101 qt_assert_x(__FUNCTION__, "Invalid resource type", __FILE__, __LINE__); 0102 return {}; 0103 } 0104 0105 // ensure directory exists or is created 0106 QFileInfo fileInfo(fullPath); 0107 if (fileInfo.exists()) { 0108 if (fileInfo.isDir()) { 0109 return fullPath; 0110 } else { 0111 qCWarning(AKONADIPRIVATE_LOG) << "StandardDirs::saveDir: '" << fileInfo.absoluteFilePath() << "' exists but is not a directory"; 0112 } 0113 } else { 0114 if (!QDir::home().mkpath(fileInfo.absoluteFilePath())) { 0115 qCWarning(AKONADIPRIVATE_LOG) << "StandardDirs::saveDir: failed to create directory '" << fileInfo.absoluteFilePath() << "'"; 0116 } else { 0117 return fullPath; 0118 } 0119 } 0120 0121 return {}; 0122 } 0123 0124 QString StandardDirs::locateResourceFile(const char *resource, const QString &relPath) 0125 { 0126 const QString fullRelPath = buildFullRelPath(resource, relPath); 0127 QList<QStandardPaths::StandardLocation> userLocations; 0128 QStandardPaths::StandardLocation genericLocation; 0129 if (qstrncmp(resource, "config", 6) == 0) { 0130 userLocations = {QStandardPaths::AppConfigLocation, QStandardPaths::ConfigLocation}; 0131 genericLocation = QStandardPaths::GenericConfigLocation; 0132 } else if (qstrncmp(resource, "data", 4) == 0) { 0133 userLocations = {QStandardPaths::AppLocalDataLocation, QStandardPaths::AppDataLocation}; 0134 genericLocation = QStandardPaths::GenericDataLocation; 0135 } else { 0136 qt_assert_x(__FUNCTION__, "Invalid resource type", __FILE__, __LINE__); 0137 return {}; 0138 } 0139 0140 const auto locateFile = [](QStandardPaths::StandardLocation location, const QString &relPath) -> QString { 0141 const auto path = QStandardPaths::locate(location, relPath); 0142 if (!path.isEmpty()) { 0143 QFileInfo file(path); 0144 if (file.exists() && file.isFile() && file.isReadable()) { 0145 return path; 0146 } 0147 } 0148 return {}; 0149 }; 0150 0151 // Always honor instance in user-specific locations 0152 for (const auto location : std::as_const(userLocations)) { 0153 const auto path = locateFile(location, fullRelPath); 0154 if (!path.isEmpty()) { 0155 return path; 0156 } 0157 } 0158 0159 const auto configPath = QStringLiteral(CONFIG_INSTALL_DIR); 0160 if (!configPath.isEmpty()) { 0161 QFileInfo file(configPath); 0162 if (file.exists() && file.isFile() && file.isReadable()) { 0163 return configPath; 0164 } 0165 } 0166 0167 // First try instance-specific path in generic locations 0168 auto path = locateFile(genericLocation, fullRelPath); 0169 if (!path.isEmpty()) { 0170 return path; 0171 } 0172 0173 // Fallback to global instance path in generic locations 0174 path = locateFile(genericLocation, QLatin1StringView("/akonadi/") + relPath); 0175 if (!path.isEmpty()) { 0176 return path; 0177 } 0178 0179 return {}; 0180 } 0181 0182 QStringList StandardDirs::locateAllResourceDirs(const QString &relPath) 0183 { 0184 return QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, relPath, QStandardPaths::LocateDirectory); 0185 } 0186 0187 QString StandardDirs::findExecutable(const QString &executableName) 0188 { 0189 QString executable = QStandardPaths::findExecutable(executableName, {qApp->applicationDirPath()}); 0190 if (executable.isEmpty()) { 0191 executable = QStandardPaths::findExecutable(executableName); 0192 } 0193 return executable; 0194 }