File indexing completed on 2024-04-21 05:48:34
0001 /* 0002 SPDX-FileCopyrightText: 2016 ROSA 0003 SPDX-License-Identifier: GPL-3.0-or-later 0004 */ 0005 0006 //////////////////////////////////////////////////////////////////////////////// 0007 // Implementation of PhysicalDevice 0008 0009 #include <KLocalizedString> 0010 0011 #include "physicaldevice.h" 0012 0013 #include <QtDBus/QDBusArgument> 0014 #include <QtDBus/QDBusReply> 0015 #include <QtDBus/QDBusInterface> 0016 #include <QtDBus/QDBusUnixFileDescriptor> 0017 #include <fcntl.h> 0018 0019 typedef QHash<QString, QVariant> Properties; 0020 typedef QHash<QString, Properties> InterfacesAndProperties; 0021 typedef QHash<QDBusObjectPath, InterfacesAndProperties> DBusIntrospection; 0022 Q_DECLARE_METATYPE(Properties) 0023 Q_DECLARE_METATYPE(InterfacesAndProperties) 0024 Q_DECLARE_METATYPE(DBusIntrospection) 0025 0026 PhysicalDevice::PhysicalDevice(const QString& name) : 0027 QFile(name) 0028 { 0029 } 0030 0031 // Opens the selected device in WriteOnly mode 0032 bool PhysicalDevice::open() 0033 { 0034 #if defined(Q_OS_WIN32) 0035 DWORD bret; 0036 0037 // In Windows QFile with write mode uses disposition OPEN_ALWAYS, but WinAPI 0038 // requires OPEN_EXISTING for physical devices. Therefore we have to use native API. 0039 m_fileHandle = CreateFile( 0040 reinterpret_cast<const wchar_t*>(fileName().utf16()), 0041 GENERIC_WRITE, 0042 FILE_SHARE_READ | FILE_SHARE_WRITE, 0043 NULL, 0044 OPEN_EXISTING, 0045 FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, 0046 NULL 0047 ); 0048 if (m_fileHandle == INVALID_HANDLE_VALUE) 0049 { 0050 setErrorString(errorMessageFromCode()); 0051 return false; 0052 } 0053 // Lock the opened device 0054 if (!DeviceIoControl(m_fileHandle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bret, NULL)) 0055 { 0056 setErrorString(formatErrorMessageFromCode(i18n("Could not acquire lock:"))); 0057 return false; 0058 } 0059 // Construct QFile around the device handle; close() will now close the handle automatically 0060 if (QFile::open(_open_osfhandle(reinterpret_cast<intptr_t>(m_fileHandle), 0), QIODevice::WriteOnly | QIODevice::Unbuffered, AutoCloseHandle)) 0061 return true; 0062 else 0063 { 0064 CloseHandle(m_fileHandle); 0065 return false; 0066 } 0067 #elif defined(Q_OS_MAC) 0068 return QFile::open(QIODevice::WriteOnly); 0069 #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) 0070 int fd = getDescriptor(); 0071 return QFile::open(fd, QIODevice::WriteOnly); 0072 #else 0073 return false; 0074 #endif 0075 } 0076 0077 #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) 0078 int PhysicalDevice::getDescriptor() { 0079 // fileName == e.g. /org/freedesktop/UDisks2/block_devices/sda 0080 // drivePath == e.g. /org/freedesktop/UDisks2/drives/JetFlash_Transcend_8GB_2H1NKR5V 0081 QDBusInterface device("org.freedesktop.UDisks2", fileName(), "org.freedesktop.UDisks2.Block", QDBusConnection::systemBus(), this); 0082 QString drivePath = qvariant_cast<QDBusObjectPath>(device.property("Drive")).path(); 0083 QDBusInterface manager("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2", "org.freedesktop.DBus.ObjectManager", QDBusConnection::systemBus()); 0084 QDBusMessage message = manager.call("GetManagedObjects"); 0085 0086 if (message.arguments().length() == 1) { 0087 QDBusArgument arg = qvariant_cast<QDBusArgument>(message.arguments().first()); 0088 DBusIntrospection objects; 0089 arg >> objects; 0090 for (auto i : objects.keys()) { 0091 if (objects[i].contains("org.freedesktop.UDisks2.Filesystem")) { 0092 QString currentDrivePath = qvariant_cast<QDBusObjectPath>(objects[i]["org.freedesktop.UDisks2.Block"]["Drive"]).path(); 0093 if (currentDrivePath == drivePath) { 0094 QDBusInterface partition("org.freedesktop.UDisks2", i.path(), "org.freedesktop.UDisks2.Filesystem", QDBusConnection::systemBus()); 0095 message = partition.call("Unmount", Properties { {"force", true} }); 0096 } 0097 } 0098 } 0099 } else { 0100 setErrorString(message.errorMessage()); 0101 return -1; 0102 } 0103 0104 QDBusReply<QDBusUnixFileDescriptor> reply = device.call(QDBus::Block, "OpenDevice", "rw", Properties{{"flags", O_DIRECT | O_SYNC | O_CLOEXEC}} ); 0105 QDBusUnixFileDescriptor fd = reply.value(); 0106 0107 if (!fd.isValid()) { 0108 setErrorString(reply.error().message()); 0109 return -1; 0110 } 0111 0112 return fd.fileDescriptor(); 0113 } 0114 #endif 0115 0116 #include "moc_physicaldevice.cpp"