File indexing completed on 2024-05-12 04:01:51
0001 /* 0002 SPDX-FileCopyrightText: 2005-2007 Kevin Ottens <ervin@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "devicemanager_p.h" //krazy:exclude=includes (devicenotifier.h is the header file for this class) 0008 #include "devicenotifier.h" 0009 0010 #include "device.h" 0011 #include "device_p.h" 0012 #include "devices_debug.h" 0013 #include "predicate.h" 0014 #include "storageaccess.h" 0015 #include "storagevolume.h" 0016 0017 #include "ifaces/device.h" 0018 #include "ifaces/devicemanager.h" 0019 0020 #include "soliddefs_p.h" 0021 0022 #include <QDir> 0023 #include <QFileInfo> 0024 #include <QLoggingCategory> 0025 0026 #include <set> 0027 0028 Q_GLOBAL_STATIC(Solid::DeviceManagerStorage, globalDeviceStorage) 0029 0030 Solid::DeviceManagerPrivate::DeviceManagerPrivate() 0031 : m_nullDevice(new DevicePrivate(QString())) 0032 { 0033 loadBackends(); 0034 0035 const QList<QObject *> backends = managerBackends(); 0036 for (QObject *backend : backends) { 0037 connect(backend, SIGNAL(deviceAdded(QString)), this, SLOT(_k_deviceAdded(QString))); 0038 connect(backend, SIGNAL(deviceRemoved(QString)), this, SLOT(_k_deviceRemoved(QString))); 0039 } 0040 } 0041 0042 Solid::DeviceManagerPrivate::~DeviceManagerPrivate() 0043 { 0044 const QList<QObject *> backends = managerBackends(); 0045 for (QObject *backend : backends) { 0046 disconnect(backend, nullptr, this, nullptr); 0047 } 0048 0049 // take a copy as m_devicesMap is changed by Solid::DeviceManagerPrivate::_k_destroyed 0050 const auto deviceMap = m_devicesMap; 0051 for (QPointer<DevicePrivate> dev : deviceMap) { 0052 if (!dev.data()->ref.deref()) { 0053 delete dev.data(); 0054 } 0055 } 0056 0057 m_devicesMap.clear(); 0058 } 0059 0060 QList<Solid::Device> Solid::Device::allDevices() 0061 { 0062 QList<Device> list; 0063 const QList<QObject *> backends = globalDeviceStorage->managerBackends(); 0064 0065 for (QObject *backendObj : backends) { 0066 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj); 0067 0068 if (backend == nullptr) { 0069 continue; 0070 } 0071 0072 const QStringList udis = backend->allDevices(); 0073 for (const QString &udi : udis) { 0074 list.append(Device(udi)); 0075 } 0076 } 0077 0078 return list; 0079 } 0080 0081 QList<Solid::Device> Solid::Device::listFromQuery(const QString &predicate, const QString &parentUdi) 0082 { 0083 Predicate p = Predicate::fromString(predicate); 0084 0085 if (p.isValid()) { 0086 return listFromQuery(p, parentUdi); 0087 } else { 0088 return QList<Device>(); 0089 } 0090 } 0091 0092 QList<Solid::Device> Solid::Device::listFromType(const DeviceInterface::Type &type, const QString &parentUdi) 0093 { 0094 QList<Device> list; 0095 const QList<QObject *> backends = globalDeviceStorage->managerBackends(); 0096 0097 for (QObject *backendObj : backends) { 0098 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj); 0099 0100 if (backend == nullptr) { 0101 continue; 0102 } 0103 if (!backend->supportedInterfaces().contains(type)) { 0104 continue; 0105 } 0106 0107 const QStringList udis = backend->devicesFromQuery(parentUdi, type); 0108 for (const QString &udi : udis) { 0109 list.append(Device(udi)); 0110 } 0111 } 0112 0113 return list; 0114 } 0115 0116 QList<Solid::Device> Solid::Device::listFromQuery(const Predicate &predicate, const QString &parentUdi) 0117 { 0118 QList<Device> list; 0119 const QSet<DeviceInterface::Type> usedTypes = predicate.usedTypes(); 0120 const QList<QObject *> backends = globalDeviceStorage->managerBackends(); 0121 for (QObject *backendObj : backends) { 0122 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj); 0123 0124 if (backend == nullptr) { 0125 continue; 0126 } 0127 0128 QStringList udis; 0129 if (predicate.isValid()) { 0130 QSet<DeviceInterface::Type> supportedTypes = backend->supportedInterfaces(); 0131 if (supportedTypes.intersect(usedTypes).isEmpty()) { 0132 continue; 0133 } 0134 0135 QList<DeviceInterface::Type> sortedTypes = supportedTypes.values(); 0136 std::sort(sortedTypes.begin(), sortedTypes.end()); 0137 for (DeviceInterface::Type type : std::as_const(sortedTypes)) { 0138 udis += backend->devicesFromQuery(parentUdi, type); 0139 } 0140 } else { 0141 udis += backend->allDevices(); 0142 } 0143 0144 std::set<QString> seen; 0145 for (const QString &udi : std::as_const(udis)) { 0146 const auto [it, isInserted] = seen.insert(udi); 0147 if (!isInserted) { 0148 continue; 0149 } 0150 Device dev(udi); 0151 0152 bool matches = false; 0153 0154 if (!predicate.isValid()) { 0155 matches = true; 0156 } else { 0157 matches = predicate.matches(dev); 0158 } 0159 0160 if (matches) { 0161 list.append(dev); 0162 } 0163 } 0164 } 0165 0166 return list; 0167 } 0168 0169 Solid::Device Solid::Device::storageAccessFromPath(const QString &path) 0170 { 0171 if (!QFileInfo::exists(path)) { 0172 qCWarning(Frontend::DeviceManager::DEVICEMANAGER).nospace() << "Couldn't get StorageAccess for \"" << path << "\" - File doesn't exist"; 0173 return Device(); 0174 } 0175 // We ensure file and all mount paths are with trailing dir separators, to avoid false positive matches later 0176 QString trailing_path(path); 0177 if (!trailing_path.endsWith(QDir::separator())) { 0178 trailing_path.append(QDir::separator()); 0179 } 0180 0181 const QList<Device> list = Solid::Device::listFromType(DeviceInterface::Type::StorageAccess); 0182 Device match; 0183 int match_length = 0; 0184 for (const Device &device : list) { 0185 auto storageVolume = device.as<StorageVolume>(); 0186 if (storageVolume && storageVolume->usage() != StorageVolume::UsageType::FileSystem) { 0187 continue; 0188 } 0189 0190 auto storageAccess = device.as<StorageAccess>(); 0191 QString mountPath = storageAccess->filePath(); 0192 if (!mountPath.endsWith(QDir::separator())) { 0193 mountPath.append(QDir::separator()); 0194 } 0195 if (mountPath.size() > match_length && trailing_path.startsWith(mountPath)) { 0196 match_length = mountPath.size(); 0197 match = device; 0198 } 0199 } 0200 return match; 0201 } 0202 0203 Solid::DeviceNotifier *Solid::DeviceNotifier::instance() 0204 { 0205 return globalDeviceStorage->notifier(); 0206 } 0207 0208 void Solid::DeviceManagerPrivate::_k_deviceAdded(const QString &udi) 0209 { 0210 if (m_devicesMap.contains(udi)) { 0211 DevicePrivate *dev = m_devicesMap[udi].data(); 0212 0213 // Ok, this one was requested somewhere was invalid 0214 // and now becomes magically valid! 0215 0216 if (dev && dev->backendObject() == nullptr) { 0217 dev->setBackendObject(createBackendObject(udi)); 0218 Q_ASSERT(dev->backendObject() != nullptr); 0219 } 0220 } 0221 0222 Q_EMIT deviceAdded(udi); 0223 } 0224 0225 void Solid::DeviceManagerPrivate::_k_deviceRemoved(const QString &udi) 0226 { 0227 if (m_devicesMap.contains(udi)) { 0228 DevicePrivate *dev = m_devicesMap[udi].data(); 0229 0230 // Ok, this one was requested somewhere was valid 0231 // and now becomes magically invalid! 0232 0233 if (dev) { 0234 Q_ASSERT(dev->backendObject() != nullptr); 0235 dev->setBackendObject(nullptr); 0236 Q_ASSERT(dev->backendObject() == nullptr); 0237 } 0238 } 0239 0240 Q_EMIT deviceRemoved(udi); 0241 } 0242 0243 void Solid::DeviceManagerPrivate::_k_destroyed(QObject *object) 0244 { 0245 QString udi = m_reverseMap.take(object); 0246 0247 if (!udi.isEmpty()) { 0248 m_devicesMap.remove(udi); 0249 } 0250 } 0251 0252 Solid::DevicePrivate *Solid::DeviceManagerPrivate::findRegisteredDevice(const QString &udi) 0253 { 0254 if (udi.isEmpty()) { 0255 return m_nullDevice.data(); 0256 } else if (m_devicesMap.contains(udi)) { 0257 return m_devicesMap[udi].data(); 0258 } else { 0259 Ifaces::Device *iface = createBackendObject(udi); 0260 0261 DevicePrivate *devData = new DevicePrivate(udi); 0262 devData->setBackendObject(iface); 0263 0264 QPointer<DevicePrivate> ptr(devData); 0265 m_devicesMap[udi] = ptr; 0266 m_reverseMap[devData] = udi; 0267 0268 connect(devData, SIGNAL(destroyed(QObject *)), this, SLOT(_k_destroyed(QObject *))); 0269 0270 return devData; 0271 } 0272 } 0273 0274 Solid::Ifaces::Device *Solid::DeviceManagerPrivate::createBackendObject(const QString &udi) 0275 { 0276 const QList<QObject *> backends = globalDeviceStorage->managerBackends(); 0277 0278 for (QObject *backendObj : backends) { 0279 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj); 0280 0281 if (backend == nullptr) { 0282 continue; 0283 } 0284 if (!udi.startsWith(backend->udiPrefix())) { 0285 continue; 0286 } 0287 0288 Ifaces::Device *iface = nullptr; 0289 0290 QObject *object = backend->createDevice(udi); 0291 iface = qobject_cast<Ifaces::Device *>(object); 0292 0293 if (iface == nullptr) { 0294 delete object; 0295 } 0296 0297 return iface; 0298 } 0299 0300 return nullptr; 0301 } 0302 0303 Solid::DeviceManagerStorage::DeviceManagerStorage() 0304 { 0305 } 0306 0307 QList<QObject *> Solid::DeviceManagerStorage::managerBackends() 0308 { 0309 ensureManagerCreated(); 0310 return m_storage.localData()->managerBackends(); 0311 } 0312 0313 Solid::DeviceNotifier *Solid::DeviceManagerStorage::notifier() 0314 { 0315 ensureManagerCreated(); 0316 return m_storage.localData(); 0317 } 0318 0319 void Solid::DeviceManagerStorage::ensureManagerCreated() 0320 { 0321 if (!m_storage.hasLocalData()) { 0322 m_storage.setLocalData(new DeviceManagerPrivate()); 0323 } 0324 } 0325 0326 #include "moc_devicemanager_p.cpp" 0327 #include "moc_devicenotifier.cpp"