1/*
2 SPDX-FileCopyrightText: 2010 Michael Zanetti <mzanetti@kde.org>
3 SPDX-FileCopyrightText: 2010-2012 Lukáš Tinkl <ltinkl@redhat.com>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#include "udisksdevice.h"
9#include "udisks_debug.h"
10#include "udisksblock.h"
11#include "udisksdeviceinterface.h"
12#include "udisksgenericinterface.h"
13#include "udisksmanager.h"
14#include "udisksopticaldisc.h"
15#include "udisksopticaldrive.h"
16#include "udisksstorageaccess.h"
17#include "udisksstoragevolume.h"
18
19#include <solid/device.h>
20#include <solid/genericinterface.h>
21
22#include <QLocale>
23#include <QMimeDatabase>
24
25using namespace Solid::Backends::UDisks2;
26
27// Adapted from KLocale as Solid needs to be Qt-only
28static QString formatByteSize(double size)
29{
30 // Per IEC 60027-2
31
32 // Binary prefixes
33 // Tebi-byte TiB 2^40 1,099,511,627,776 bytes
34 // Gibi-byte GiB 2^30 1,073,741,824 bytes
35 // Mebi-byte MiB 2^20 1,048,576 bytes
36 // Kibi-byte KiB 2^10 1,024 bytes
37
38 QString s;
39 // Gibi-byte
40 if (size >= 1073741824.0) {
41 size /= 1073741824.0;
42 if (size > 1024) { // Tebi-byte
43 s = QCoreApplication::translate(context: "udisksdevice", key: "%1 TiB").arg(a: QLocale().toString(f: size / 1024.0, format: 'f', precision: 1));
44 } else {
45 s = QCoreApplication::translate(context: "udisksdevice", key: "%1 GiB").arg(a: QLocale().toString(f: size, format: 'f', precision: 1));
46 }
47 }
48 // Mebi-byte
49 else if (size >= 1048576.0) {
50 size /= 1048576.0;
51 s = QCoreApplication::translate(context: "udisksdevice", key: "%1 MiB").arg(a: QLocale().toString(f: size, format: 'f', precision: 1));
52 }
53 // Kibi-byte
54 else if (size >= 1024.0) {
55 size /= 1024.0;
56 s = QCoreApplication::translate(context: "udisksdevice", key: "%1 KiB").arg(a: QLocale().toString(f: size, format: 'f', precision: 1));
57 }
58 // Just byte
59 else if (size > 0) {
60 s = QCoreApplication::translate(context: "udisksdevice", key: "%1 B").arg(a: QLocale().toString(f: size, format: 'f', precision: 1));
61 }
62 // Nothing
63 else {
64 s = QCoreApplication::translate(context: "udisksdevice", key: "0 B");
65 }
66 return s;
67}
68
69static QString concatBlockDeviceDescription(const QString &name, qulonglong size, bool isExternal)
70{
71 QString description;
72 if (size > 0) {
73 const QString sizeStr = formatByteSize(size);
74 if (isExternal) {
75 description = QObject::tr(s: "%1 External Drive (%2)", c: "%1 is the size, %2 is the block device name e.g. sda, sda1").arg(args: sizeStr, args: name);
76 } else {
77 description = QObject::tr(s: "%1 Internal Drive (%2)", c: "%1 is the size, %2 is the block device name e.g. sda, sda1").arg(args: sizeStr, args: name);
78 }
79 } else {
80 if (isExternal) {
81 description = QObject::tr(s: "External Drive (%1)", c: "%1 is the block device name e.g. sda, sda1").arg(a: name);
82 } else {
83 description = QObject::tr(s: "Internal Drive (%1)", c: "%1 is the block device name e.g. sda, sda1").arg(a: name);
84 }
85 }
86
87 return description;
88}
89
90Device::Device(Manager *manager, const QString &udi)
91 : Solid::Ifaces::Device()
92 , m_manager(manager)
93 , m_udi(udi)
94{
95 connect(sender: m_manager, signal: &Manager::propertyChanged, context: this, slot: [this](const QString &udi, const QMap<QString, int> &changes) {
96 if (udi == m_udi) {
97 Q_EMIT propertyChanged(changes);
98 Q_EMIT changed();
99 }
100 });
101}
102
103Device::~Device()
104{
105}
106
107QString Device::udi() const
108{
109 return m_udi;
110}
111
112QVariant Device::prop(const QString &key) const
113{
114 return m_manager->deviceProperty(udi: m_udi, name: key);
115}
116
117bool Device::propertyExists(const QString &key) const
118{
119 return m_manager->deviceProperty(udi: m_udi, name: key, fetchMode: Manager::CachedOnly).isValid();
120}
121
122QVariantMap Device::allProperties() const
123{
124 QVariantMap flattened;
125
126 const auto interfaces = m_manager->deviceProperties(udi: m_udi);
127
128 // Flatten per-interface properties into a single map.
129 // We iterate the interfaces in reverse since Manager::prop() returns the *first*
130 // property found, so we'll override any other properties that way.
131 // FIXME actually reverse it lol, no rbegin on QMap :(
132 for (const auto &props : interfaces) {
133 flattened.insert(map: props);
134 }
135
136 return flattened;
137}
138
139bool Device::hasInterface(const QString &name) const
140{
141 return m_manager->hasInterface(udi: m_udi, interface: name);
142}
143
144Manager *Device::manager() const
145{
146 return m_manager;
147}
148
149QObject *Device::createDeviceInterface(const Solid::DeviceInterface::Type &type)
150{
151 if (!queryDeviceInterface(type)) {
152 return nullptr;
153 }
154
155 DeviceInterface *iface = nullptr;
156 switch (type) {
157 case Solid::DeviceInterface::GenericInterface:
158 iface = new GenericInterface(this);
159 break;
160 case Solid::DeviceInterface::Block:
161 iface = new Block(this);
162 break;
163 case Solid::DeviceInterface::StorageAccess:
164 iface = new StorageAccess(this);
165 break;
166 case Solid::DeviceInterface::StorageDrive:
167 iface = new StorageDrive(this);
168 break;
169 case Solid::DeviceInterface::OpticalDrive:
170 iface = new OpticalDrive(this);
171 break;
172 case Solid::DeviceInterface::StorageVolume:
173 iface = new StorageVolume(this);
174 break;
175 case Solid::DeviceInterface::OpticalDisc:
176 iface = new OpticalDisc(this);
177 break;
178 default:
179 break;
180 }
181 return iface;
182}
183
184bool Device::queryDeviceInterface(const Solid::DeviceInterface::Type &type) const
185{
186 switch (type) {
187 case Solid::DeviceInterface::GenericInterface:
188 return true;
189 case Solid::DeviceInterface::Block:
190 return isBlock() || isDrive();
191 case Solid::DeviceInterface::StorageVolume:
192 return isStorageVolume();
193 case Solid::DeviceInterface::StorageAccess:
194 return isStorageAccess();
195 case Solid::DeviceInterface::StorageDrive:
196 return isDrive();
197 case Solid::DeviceInterface::OpticalDrive:
198 return isOpticalDrive();
199 case Solid::DeviceInterface::OpticalDisc:
200 return isOpticalDisc();
201 default:
202 return false;
203 }
204}
205
206QStringList Device::emblems() const
207{
208 if (queryDeviceInterface(type: Solid::DeviceInterface::StorageAccess)) {
209 const UDisks2::StorageAccess accessIface(const_cast<Device *>(this));
210 if (accessIface.isAccessible()) {
211 if (isEncryptedContainer()) {
212 return {QStringLiteral("emblem-encrypted-unlocked")};
213 }
214 } else {
215 if (isEncryptedContainer()) {
216 return {QStringLiteral("emblem-encrypted-locked")};
217 } else {
218 return {QStringLiteral("emblem-unmounted")};
219 }
220 }
221 }
222
223 return {};
224}
225
226QString Device::description() const
227{
228 const QString hintName = property(name: "HintName").toString(); // non-cached
229 if (!hintName.isEmpty()) {
230 return hintName;
231 }
232
233 if (isLoop()) {
234 return loopDescription();
235 } else if (isSwap()) {
236 return tr(s: "Swap Space");
237 } else if (queryDeviceInterface(type: Solid::DeviceInterface::StorageDrive)) {
238 return storageDescription();
239 } else if (queryDeviceInterface(type: Solid::DeviceInterface::StorageVolume)) {
240 return volumeDescription();
241 } else {
242 return product();
243 }
244}
245
246QString Device::loopDescription() const
247{
248 const QString label = prop(QStringLiteral("IdLabel")).toString();
249 if (!label.isEmpty()) {
250 return label;
251 }
252
253 const QString backingFile = prop(QStringLiteral("BackingFile")).toString();
254 if (!backingFile.isEmpty()) {
255 return backingFile.section(asep: QLatin1Char('/'), astart: -1);
256 }
257
258 return tr(s: "Loop Device");
259}
260
261QString Device::storageDescription() const
262{
263 QString description;
264 const UDisks2::StorageDrive storageDrive(const_cast<Device *>(this));
265 Solid::StorageDrive::DriveType drive_type = storageDrive.driveType();
266 const bool drive_is_hotpluggable = storageDrive.isHotpluggable();
267
268 if (drive_type == Solid::StorageDrive::CdromDrive) {
269 const UDisks2::OpticalDrive opticalDrive(const_cast<Device *>(this));
270 Solid::OpticalDrive::MediumTypes mediumTypes = opticalDrive.supportedMedia();
271 QString first;
272 QString second;
273
274 first = tr(s: "CD-ROM", c: "First item of %1%2 Drive sentence");
275 if (mediumTypes & Solid::OpticalDrive::Cdr) {
276 first = tr(s: "CD-R", c: "First item of %1%2 Drive sentence");
277 }
278 if (mediumTypes & Solid::OpticalDrive::Cdrw) {
279 first = tr(s: "CD-RW", c: "First item of %1%2 Drive sentence");
280 }
281
282 if (mediumTypes & Solid::OpticalDrive::Dvd) {
283 second = tr(s: "/DVD-ROM", c: "Second item of %1%2 Drive sentence");
284 }
285 if (mediumTypes & Solid::OpticalDrive::Dvdplusr) {
286 second = tr(s: "/DVD+R", c: "Second item of %1%2 Drive sentence");
287 }
288 if (mediumTypes & Solid::OpticalDrive::Dvdplusrw) {
289 second = tr(s: "/DVD+RW", c: "Second item of %1%2 Drive sentence");
290 }
291 if (mediumTypes & Solid::OpticalDrive::Dvdr) {
292 second = tr(s: "/DVD-R", c: "Second item of %1%2 Drive sentence");
293 }
294 if (mediumTypes & Solid::OpticalDrive::Dvdrw) {
295 second = tr(s: "/DVD-RW", c: "Second item of %1%2 Drive sentence");
296 }
297 if (mediumTypes & Solid::OpticalDrive::Dvdram) {
298 second = tr(s: "/DVD-RAM", c: "Second item of %1%2 Drive sentence");
299 }
300 if ((mediumTypes & Solid::OpticalDrive::Dvdr) && (mediumTypes & Solid::OpticalDrive::Dvdplusr)) {
301 if (mediumTypes & Solid::OpticalDrive::Dvdplusdl) {
302 second = tr(s: "/DVD±R DL", c: "Second item of %1%2 Drive sentence");
303 } else {
304 second = tr(s: "/DVD±R", c: "Second item of %1%2 Drive sentence");
305 }
306 }
307 if ((mediumTypes & Solid::OpticalDrive::Dvdrw) && (mediumTypes & Solid::OpticalDrive::Dvdplusrw)) {
308 if ((mediumTypes & Solid::OpticalDrive::Dvdplusdl) || (mediumTypes & Solid::OpticalDrive::Dvdplusdlrw)) {
309 second = tr(s: "/DVD±RW DL", c: "Second item of %1%2 Drive sentence");
310 } else {
311 second = tr(s: "/DVD±RW", c: "Second item of %1%2 Drive sentence");
312 }
313 }
314 if (mediumTypes & Solid::OpticalDrive::Bd) {
315 second = tr(s: "/BD-ROM", c: "Second item of %1%2 Drive sentence");
316 }
317 if (mediumTypes & Solid::OpticalDrive::Bdr) {
318 second = tr(s: "/BD-R", c: "Second item of %1%2 Drive sentence");
319 }
320 if (mediumTypes & Solid::OpticalDrive::Bdre) {
321 second = tr(s: "/BD-RE", c: "Second item of %1%2 Drive sentence");
322 }
323 if (mediumTypes & Solid::OpticalDrive::HdDvd) {
324 second = tr(s: "/HD DVD-ROM", c: "Second item of %1%2 Drive sentence");
325 }
326 if (mediumTypes & Solid::OpticalDrive::HdDvdr) {
327 second = tr(s: "/HD DVD-R", c: "Second item of %1%2 Drive sentence");
328 }
329 if (mediumTypes & Solid::OpticalDrive::HdDvdrw) {
330 second = tr(s: "/HD DVD-RW", c: "Second item of %1%2 Drive sentence");
331 }
332
333 if (drive_is_hotpluggable) {
334 description = tr(s: "External %1%2 Drive", c: "%1 is CD-ROM/CD-R/etc; %2 is '/DVD-ROM'/'/DVD-R'/etc (with leading slash)").arg(args&: first, args&: second);
335 } else {
336 description = tr(s: "%1%2 Drive", c: "%1 is CD-ROM/CD-R/etc; %2 is '/DVD-ROM'/'/DVD-R'/etc (with leading slash)").arg(args&: first, args&: second);
337 }
338
339 return description;
340 }
341
342 if (drive_type == Solid::StorageDrive::Floppy) {
343 if (drive_is_hotpluggable) {
344 description = tr(s: "External Floppy Drive");
345 } else {
346 description = tr(s: "Floppy Drive");
347 }
348
349 return description;
350 }
351
352 const bool drive_is_removable = storageDrive.isRemovable();
353
354 if (drive_type == Solid::StorageDrive::HardDisk && !drive_is_removable) {
355 QString devName = storageDrive.device();
356 devName.remove(s: QLatin1String("/dev/"));
357 description = concatBlockDeviceDescription(name: devName, size: storageDrive.size(), isExternal: drive_is_hotpluggable);
358
359 return description;
360 }
361
362 QString vendormodel_str;
363 QString model = product();
364 QString vendor_str = vendor();
365
366 if (vendor_str.isEmpty()) {
367 if (!model.isEmpty()) {
368 vendormodel_str = model;
369 }
370 } else {
371 if (model.isEmpty()) {
372 vendormodel_str = vendor_str;
373 } else {
374 if (model.startsWith(s: vendor_str)) {
375 // e.g. vendor is "Nokia" and model is "Nokia N950" we do not want "Nokia Nokia N950" as description
376 vendormodel_str = model;
377 } else {
378 vendormodel_str = tr(s: "%1 %2", c: "%1 is the vendor, %2 is the model of the device").arg(args&: vendor_str, args&: model);
379 }
380 }
381 }
382
383 if (vendormodel_str.isEmpty()) {
384 description = tr(s: "Drive");
385 } else {
386 description = vendormodel_str;
387 }
388
389 return description;
390}
391
392QString Device::volumeDescription() const
393{
394 QString description;
395 const UDisks2::StorageVolume storageVolume(const_cast<Device *>(this));
396 QString volume_label = prop(QStringLiteral("IdLabel")).toString();
397 if (volume_label.isEmpty()) {
398 volume_label = prop(QStringLiteral("Name")).toString();
399 }
400 if (!volume_label.isEmpty()) {
401 return volume_label;
402 }
403
404 UDisks2::Device storageDevice(manager(), drivePath());
405 const UDisks2::StorageDrive storageDrive(&storageDevice);
406 Solid::StorageDrive::DriveType drive_type = storageDrive.driveType();
407
408 // Handle media in optical drives
409 if (drive_type == Solid::StorageDrive::CdromDrive) {
410 const UDisks2::OpticalDisc disc(const_cast<Device *>(this));
411 switch (disc.discType()) {
412 case Solid::OpticalDisc::UnknownDiscType:
413 case Solid::OpticalDisc::CdRom:
414 description = tr(s: "CD-ROM");
415 break;
416
417 case Solid::OpticalDisc::CdRecordable:
418 if (disc.isBlank()) {
419 description = tr(s: "Blank CD-R");
420 } else {
421 description = tr(s: "CD-R");
422 }
423 break;
424
425 case Solid::OpticalDisc::CdRewritable:
426 if (disc.isBlank()) {
427 description = tr(s: "Blank CD-RW");
428 } else {
429 description = tr(s: "CD-RW");
430 }
431 break;
432
433 case Solid::OpticalDisc::DvdRom:
434 description = tr(s: "DVD-ROM");
435 break;
436
437 case Solid::OpticalDisc::DvdRam:
438 if (disc.isBlank()) {
439 description = tr(s: "Blank DVD-RAM");
440 } else {
441 description = tr(s: "DVD-RAM");
442 }
443 break;
444
445 case Solid::OpticalDisc::DvdRecordable:
446 if (disc.isBlank()) {
447 description = tr(s: "Blank DVD-R");
448 } else {
449 description = tr(s: "DVD-R");
450 }
451 break;
452
453 case Solid::OpticalDisc::DvdPlusRecordableDuallayer:
454 if (disc.isBlank()) {
455 description = tr(s: "Blank DVD+R Dual-Layer");
456 } else {
457 description = tr(s: "DVD+R Dual-Layer");
458 }
459 break;
460
461 case Solid::OpticalDisc::DvdRewritable:
462 if (disc.isBlank()) {
463 description = tr(s: "Blank DVD-RW");
464 } else {
465 description = tr(s: "DVD-RW");
466 }
467 break;
468
469 case Solid::OpticalDisc::DvdPlusRecordable:
470 if (disc.isBlank()) {
471 description = tr(s: "Blank DVD+R");
472 } else {
473 description = tr(s: "DVD+R");
474 }
475 break;
476
477 case Solid::OpticalDisc::DvdPlusRewritable:
478 if (disc.isBlank()) {
479 description = tr(s: "Blank DVD+RW");
480 } else {
481 description = tr(s: "DVD+RW");
482 }
483 break;
484
485 case Solid::OpticalDisc::DvdPlusRewritableDuallayer:
486 if (disc.isBlank()) {
487 description = tr(s: "Blank DVD+RW Dual-Layer");
488 } else {
489 description = tr(s: "DVD+RW Dual-Layer");
490 }
491 break;
492
493 case Solid::OpticalDisc::BluRayRom:
494 description = tr(s: "BD-ROM");
495 break;
496
497 case Solid::OpticalDisc::BluRayRecordable:
498 if (disc.isBlank()) {
499 description = tr(s: "Blank BD-R");
500 } else {
501 description = tr(s: "BD-R");
502 }
503 break;
504
505 case Solid::OpticalDisc::BluRayRewritable:
506 if (disc.isBlank()) {
507 description = tr(s: "Blank BD-RE");
508 } else {
509 description = tr(s: "BD-RE");
510 }
511 break;
512
513 case Solid::OpticalDisc::HdDvdRom:
514 description = tr(s: "HD DVD-ROM");
515 break;
516
517 case Solid::OpticalDisc::HdDvdRecordable:
518 if (disc.isBlank()) {
519 description = tr(s: "Blank HD DVD-R");
520 } else {
521 description = tr(s: "HD DVD-R");
522 }
523 break;
524
525 case Solid::OpticalDisc::HdDvdRewritable:
526 if (disc.isBlank()) {
527 description = tr(s: "Blank HD DVD-RW");
528 } else {
529 description = tr(s: "HD DVD-RW");
530 }
531 break;
532 }
533
534 // Special case for pure audio disc
535 if (disc.availableContent() == Solid::OpticalDisc::Audio) {
536 description = tr(s: "Audio CD");
537 }
538
539 return description;
540 }
541
542 const bool drive_is_removable = storageDrive.isRemovable();
543
544 QString size_str = formatByteSize(size: storageVolume.size());
545 QString volumeName = storageVolume.device();
546 volumeName.remove(s: QLatin1String("/dev/"));
547 if (isEncryptedContainer()) {
548 if (storageVolume.size() > 0) {
549 description = tr(s: "%1 Encrypted Drive", c: "%1 is the size").arg(a: size_str);
550 } else {
551 description = tr(s: "Encrypted Drive");
552 }
553 } else if (drive_type == Solid::StorageDrive::HardDisk && !drive_is_removable) {
554 description = concatBlockDeviceDescription(name: volumeName, size: storageVolume.size(), isExternal: storageDrive.isHotpluggable());
555 } else if (drive_type == Solid::StorageDrive::Floppy) {
556 description = tr(s: "Floppy Disk");
557 } else {
558 if (drive_is_removable) {
559 if (storageVolume.size() > 0) {
560 description = tr(s: "%1 Removable Media", c: "%1 is the size").arg(a: size_str);
561 } else {
562 description = tr(s: "Removable Media");
563 }
564 } else {
565 if (storageVolume.size() > 0) {
566 description = tr(s: "%1 Media", c: "%1 is the size").arg(a: size_str);
567 } else {
568 description = tr(s: "Storage Media");
569 }
570 }
571 }
572
573 return description;
574}
575
576QString Device::icon() const
577{
578 QString iconName = property(name: "HintIconName").toString(); // non-cached
579
580 if (!iconName.isEmpty()) {
581 return iconName;
582 } else if (isRoot()) {
583 return QStringLiteral("drive-harddisk-root");
584 } else if (isLoop()) {
585 const QString backingFile = prop(QStringLiteral("BackingFile")).toString();
586 if (!backingFile.isEmpty()) {
587 QMimeType type = QMimeDatabase().mimeTypeForFile(fileName: backingFile);
588 if (!type.isDefault()) {
589 return type.iconName();
590 }
591 }
592 return QStringLiteral("drive-harddisk");
593 } else if (isSwap()) {
594 return QStringLiteral("drive-harddisk");
595 } else if (isDrive()) {
596 const bool isRemovable = prop(QStringLiteral("Removable")).toBool();
597 const QString conn = prop(QStringLiteral("ConnectionBus")).toString();
598
599 if (isOpticalDrive()) {
600 return QStringLiteral("drive-optical");
601 } else if (isRemovable && !prop(QStringLiteral("Optical")).toBool()) {
602 if (conn == QLatin1String("usb")) {
603 return QStringLiteral("drive-removable-media-usb");
604 } else {
605 return QStringLiteral("drive-removable-media");
606 }
607 }
608 } else if (isBlock()) {
609 const QString drv = drivePath();
610 if (drv.isEmpty() || drv == QLatin1String("/")) {
611 return QStringLiteral("drive-harddisk"); // stuff like loop devices or swap which don't have the Drive prop set
612 }
613
614 Device drive(manager(), drv);
615
616 // handle media
617 const QString media = drive.prop(QStringLiteral("Media")).toString();
618
619 if (!media.isEmpty()) {
620 if (drive.prop(QStringLiteral("Optical")).toBool()) { // optical stuff
621 bool isWritable = drive.prop(QStringLiteral("OpticalBlank")).toBool();
622
623 const UDisks2::OpticalDisc disc(const_cast<Device *>(this));
624 Solid::OpticalDisc::ContentTypes availContent = disc.availableContent();
625
626 if (availContent & Solid::OpticalDisc::VideoDvd) { // Video DVD
627 return QStringLiteral("media-optical-dvd-video");
628 } else if ((availContent & Solid::OpticalDisc::VideoCd) || (availContent & Solid::OpticalDisc::SuperVideoCd)) { // Video CD
629 return QStringLiteral("media-optical-video");
630 } else if ((availContent & Solid::OpticalDisc::Data) && (availContent & Solid::OpticalDisc::Audio)) { // Mixed CD
631 return QStringLiteral("media-optical-mixed-cd");
632 } else if (availContent & Solid::OpticalDisc::Audio) { // Audio CD
633 return QStringLiteral("media-optical-audio");
634 } else if (availContent & Solid::OpticalDisc::Data) { // Data CD
635 return QStringLiteral("media-optical-data");
636 } else if (isWritable) {
637 return QStringLiteral("media-optical-recordable");
638 } else {
639 if (media.startsWith(QStringLiteral("optical_dvd")) || media.startsWith(QStringLiteral("optical_hddvd"))) { // DVD
640 return QStringLiteral("media-optical-dvd");
641 } else if (media.startsWith(QStringLiteral("optical_bd"))) { // BluRay
642 return QStringLiteral("media-optical-blu-ray");
643 }
644 }
645
646 // fallback for every other optical disc
647 return QStringLiteral("media-optical");
648 }
649
650 if (media == QLatin1String("flash_ms")) { // Flash & Co.
651 return QStringLiteral("media-flash-memory-stick");
652 } else if (media == QLatin1String("flash_sd") //
653 || media == QLatin1String("flash_sdhc") //
654 || media == QLatin1String("flash_sdxc") //
655 || media == QLatin1String("flash_mmc")) {
656 return QStringLiteral("media-flash-sd-mmc");
657 } else if (media == QLatin1String("flash_sm")) {
658 return QStringLiteral("media-flash-smart-media");
659 } else if (media == QLatin1String("thumb")) {
660 return QStringLiteral("drive-removable-media-usb-pendrive");
661 } else if (media.startsWith(QStringLiteral("flash"))) {
662 return QStringLiteral("media-flash");
663 } else if (media == QLatin1String("floppy")) { // the good ol' floppy
664 return QStringLiteral("media-floppy");
665 }
666 }
667
668 if (drive.prop(QStringLiteral("ConnectionBus")).toString() == QLatin1String("sdio")) { // hack for SD cards connected thru sdio bus
669 return QStringLiteral("media-flash-sd-mmc");
670 }
671
672 return drive.icon();
673 }
674
675 return QStringLiteral("drive-harddisk"); // general fallback
676}
677
678QString Device::product() const
679{
680 if (!isDrive()) {
681 Device drive(manager(), drivePath());
682 return drive.prop(QStringLiteral("Model")).toString();
683 }
684
685 return prop(QStringLiteral("Model")).toString();
686}
687
688QString Device::vendor() const
689{
690 if (!isDrive()) {
691 Device drive(manager(), drivePath());
692 return drive.prop(QStringLiteral("Vendor")).toString();
693 }
694
695 return prop(QStringLiteral("Vendor")).toString();
696}
697
698QString Device::parentUdi() const
699{
700 QString parent;
701
702 if (propertyExists(QStringLiteral("Drive"))) { // block
703 parent = drivePath();
704 } else if (propertyExists(QStringLiteral("Table"))) { // partition
705 parent = prop(QStringLiteral("Table")).value<QDBusObjectPath>().path();
706 } else if (parent.isEmpty() || parent == QLatin1String("/")) {
707 parent = QStringLiteral(UD2_UDI_DISKS_PREFIX);
708 }
709 return parent;
710}
711
712QString Device::errorToString(const QString &error) const
713{
714 if (error == QLatin1String(UD2_ERROR_UNAUTHORIZED) || error == QLatin1String(UD2_ERROR_NOT_AUTHORIZED)) {
715 return tr(s: "You are not authorized to perform this operation");
716 } else if (error == QLatin1String(UD2_ERROR_BUSY)) {
717 return tr(s: "The device is currently busy");
718 } else if (error == QLatin1String(UD2_ERROR_FAILED)) {
719 return tr(s: "The requested operation has failed");
720 } else if (error == QLatin1String(UD2_ERROR_CANCELED)) {
721 return tr(s: "The requested operation has been canceled");
722 } else if (error == QLatin1String(UD2_ERROR_INVALID_OPTION)) {
723 return tr(s: "An invalid or malformed option has been given");
724 } else if (error == QLatin1String(UD2_ERROR_MISSING_DRIVER)) {
725 return tr(s: "The kernel driver for this filesystem type is not available");
726 } else if (error == QLatin1String(UD2_ERROR_ALREADY_MOUNTED)) {
727 return tr(s: "The device is already mounted");
728 } else if (error == QLatin1String(UD2_ERROR_NOT_MOUNTED)) {
729 return tr(s: "The device is not mounted");
730 } else if (error == QLatin1String(UD2_ERROR_MOUNTED_BY_OTHER_USER)) {
731 return tr(s: "The device is mounted by another user");
732 } else if (error == QLatin1String(UD2_ERROR_ALREADY_UNMOUNTING)) {
733 return tr(s: "The device is already unmounting");
734 } else if (error == QLatin1String(UD2_ERROR_TIMED_OUT)) {
735 return tr(s: "The operation timed out");
736 } else if (error == QLatin1String(UD2_ERROR_WOULD_WAKEUP)) {
737 return tr(s: "The operation would wake up a disk that is in a deep-sleep state");
738 } else if (error == QLatin1String(UD2_ERROR_ALREADY_CANCELLED)) {
739 return tr(s: "The operation has already been canceled");
740 } else if (error == QLatin1String(UD2_ERROR_NOT_AUTHORIZED_CAN_OBTAIN)) {
741 return tr(s: "Cannot request authentication for this action. The PolicyKit authentication system appears to be not available.");
742 } else if (error == QLatin1String(UD2_ERROR_NOT_AUTHORIZED_DISMISSED)) {
743 return tr(s: "The authentication prompt was canceled");
744 } else {
745 return tr(s: "An unspecified error has occurred");
746 }
747}
748
749Solid::ErrorType Device::errorToSolidError(const QString &error) const
750{
751 if (error == QLatin1String(UD2_ERROR_BUSY)) {
752 return Solid::DeviceBusy;
753 } else if (error == QLatin1String(UD2_ERROR_FAILED)) {
754 return Solid::OperationFailed;
755 } else if (error == QLatin1String(UD2_ERROR_CANCELED)) {
756 return Solid::UserCanceled;
757 } else if (error == QLatin1String(UD2_ERROR_INVALID_OPTION)) {
758 return Solid::InvalidOption;
759 } else if (error == QLatin1String(UD2_ERROR_MISSING_DRIVER)) {
760 return Solid::MissingDriver;
761 } else if (error == QLatin1String(UD2_ERROR_NOT_AUTHORIZED_DISMISSED)) {
762 return Solid::UserCanceled;
763 } else {
764 return Solid::UnauthorizedOperation;
765 }
766}
767
768bool Device::isBlock() const
769{
770 return hasInterface(QStringLiteral(UD2_DBUS_INTERFACE_BLOCK));
771}
772
773bool Device::isPartition() const
774{
775 return hasInterface(QStringLiteral(UD2_DBUS_INTERFACE_PARTITION));
776}
777
778bool Device::isPartitionTable() const
779{
780 return hasInterface(QStringLiteral(UD2_DBUS_INTERFACE_PARTITIONTABLE));
781}
782
783bool Device::isStorageVolume() const
784{
785 return isPartition() || isPartitionTable() || isStorageAccess() || isOpticalDisc();
786}
787
788bool Device::isStorageAccess() const
789{
790 return hasInterface(QStringLiteral(UD2_DBUS_INTERFACE_FILESYSTEM)) || isEncryptedContainer();
791}
792
793bool Device::isDrive() const
794{
795 return hasInterface(QStringLiteral(UD2_DBUS_INTERFACE_DRIVE));
796}
797
798bool Device::isOpticalDrive() const
799{
800 return isDrive() && !prop(QStringLiteral("MediaCompatibility")).toStringList().filter(QStringLiteral("optical_")).isEmpty();
801}
802
803bool Device::isOpticalDisc() const
804{
805 const QString drv = drivePath();
806 if (drv.isEmpty() || drv == QLatin1String("/")) {
807 return false;
808 }
809
810 Device drive(manager(), drv);
811 return drive.prop(QStringLiteral("Optical")).toBool();
812}
813
814bool Device::mightBeOpticalDisc() const
815{
816 const QString drv = drivePath();
817 if (drv.isEmpty() || drv == QLatin1String("/")) {
818 return false;
819 }
820
821 Device drive(manager(), drv);
822 return drive.isOpticalDrive();
823}
824
825bool Device::isMounted() const
826{
827 QVariant mountPoints = prop(QStringLiteral("MountPoints"));
828 return mountPoints.isValid() && !qdbus_cast<QByteArrayList>(v: mountPoints).isEmpty();
829}
830
831bool Device::isEncryptedContainer() const
832{
833 return hasInterface(QStringLiteral(UD2_DBUS_INTERFACE_ENCRYPTED));
834}
835
836bool Device::isEncryptedCleartext() const
837{
838 const QString holderDevice = prop(QStringLiteral("CryptoBackingDevice")).value<QDBusObjectPath>().path();
839 if (holderDevice.isEmpty() || holderDevice == QLatin1String("/")) {
840 return false;
841 } else {
842 return true;
843 }
844}
845
846bool Device::isRoot() const
847{
848 if (isStorageAccess()) {
849 const UDisks2::StorageAccess accessIface(const_cast<Device *>(this));
850 return accessIface.filePath() == QLatin1String("/");
851 }
852 return false;
853}
854
855bool Device::isSwap() const
856{
857 return hasInterface(QStringLiteral(UD2_DBUS_INTERFACE_SWAP));
858}
859
860bool Device::isLoop() const
861{
862 return hasInterface(QStringLiteral(UD2_DBUS_INTERFACE_LOOP));
863}
864
865QString Device::drivePath() const
866{
867 return prop(QStringLiteral("Drive")).value<QDBusObjectPath>().path();
868}
869
870#include "moc_udisksdevice.cpp"
871

source code of solid/src/solid/devices/backends/udisks2/udisksdevice.cpp