diff --git a/kioslave/media/libmediacommon/medium.cpp b/kioslave/media/libmediacommon/medium.cpp index 9fa7ab253..ca618494e 100644 --- a/kioslave/media/libmediacommon/medium.cpp +++ b/kioslave/media/libmediacommon/medium.cpp @@ -40,6 +40,7 @@ Medium::Medium(const TQString &id, const TQString &name) m_properties+= TQString::null; /* ICON_NAME */ m_properties+= "false"; /* ENCRYPTED */ m_properties+= TQString::null; /* CLEAR_DEVICE_UDI */ + m_properties+= "false"; /* HIDDEN */ loadUserLabel(); @@ -63,6 +64,7 @@ Medium::Medium() m_properties+= TQString::null; /* ICON_NAME */ m_properties+= TQString::null; /* ENCRYPTED */ m_properties+= TQString::null; /* CLEAR_DEVICE_UDI */ + m_properties+= "false"; /* HIDDEN */ m_halmounted = false; } @@ -88,6 +90,7 @@ const Medium Medium::create(const TQStringList &properties) m.m_properties[ICON_NAME] = properties[ICON_NAME]; m.m_properties[ENCRYPTED] = properties[ENCRYPTED]; m.m_properties[CLEAR_DEVICE_UDI] = properties[CLEAR_DEVICE_UDI]; + m.m_properties[HIDDEN] = properties[HIDDEN]; } return m; @@ -134,6 +137,11 @@ void Medium::setEncrypted(bool state) m_properties[ENCRYPTED] = ( state ? "true" : "false" ); } +void Medium::setHidden(bool state) +{ + m_properties[HIDDEN] = ( state ? "true" : "false" ); +} + void Medium::setUserLabel(const TQString &label) { KConfig cfg("mediamanagerrc"); diff --git a/kioslave/media/libmediacommon/medium.h b/kioslave/media/libmediacommon/medium.h index b0eb86c33..78da6d09c 100644 --- a/kioslave/media/libmediacommon/medium.h +++ b/kioslave/media/libmediacommon/medium.h @@ -1,5 +1,5 @@ /* This file is part of the KDE Project - Copyright (c) 2004 Kévin Ottens + Copyright (c) 2004 K�vin Ottens This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -43,7 +43,8 @@ public: static const uint ICON_NAME = 11; static const uint ENCRYPTED = 12; static const uint CLEAR_DEVICE_UDI = 13; - static const uint PROPERTIES_COUNT = 14; + static const uint HIDDEN = 14; + static const uint PROPERTIES_COUNT = 15; static const TQString SEPARATOR; Medium(const TQString &id, const TQString &name); @@ -66,6 +67,7 @@ public: TQString iconName() const { return m_properties[ICON_NAME]; } bool isEncrypted() const { return m_properties[ENCRYPTED]=="true"; }; TQString clearDeviceUdi() const { return m_properties[CLEAR_DEVICE_UDI]; }; + bool hidden() const { return m_properties[HIDDEN]=="true"; }; bool needMounting() const; bool needDecryption() const; @@ -76,6 +78,7 @@ public: void setLabel(const TQString &label); void setUserLabel(const TQString &label); void setEncrypted(bool state); + void setHidden(bool state); bool mountableState(bool mounted); void mountableState(const TQString &deviceNode, diff --git a/kioslave/media/mediaimpl.cpp b/kioslave/media/mediaimpl.cpp index ccb9af0a2..97db08041 100644 --- a/kioslave/media/mediaimpl.cpp +++ b/kioslave/media/mediaimpl.cpp @@ -151,11 +151,13 @@ bool MediaImpl::listMedia(TQValueList &list) for(; it!=end; ++it) { - entry.clear(); + if (!(*it).hidden()) { + entry.clear(); - createMediumEntry(entry, *it); + createMediumEntry(entry, *it); - list.append(entry); + list.append(entry); + } } return true; diff --git a/kioslave/media/mediamanager/medialist.cpp b/kioslave/media/mediamanager/medialist.cpp index bb0de6248..6ac7dc341 100644 --- a/kioslave/media/mediamanager/medialist.cpp +++ b/kioslave/media/mediamanager/medialist.cpp @@ -162,6 +162,8 @@ bool MediaList::changeMediumState(const Medium &medium, bool allowNotification) m->setLabel( medium.label() ); } + m->setHidden(medium.hidden()); + emit mediumStateChanged(m->id(), m->name(), !m->needMounting(), allowNotification); return true; } diff --git a/kioslave/media/mediamanager/mediamanager.cpp b/kioslave/media/mediamanager/mediamanager.cpp index 5510a4b17..6223036a6 100644 --- a/kioslave/media/mediamanager/mediamanager.cpp +++ b/kioslave/media/mediamanager/mediamanager.cpp @@ -199,10 +199,12 @@ TQStringList MediaManager::properties(const TQString &name) } } - if (m) + if (m) { return m->properties(); - else + } + else { return TQStringList(); + } } TQStringList MediaManager::mountoptions(const TQString &name) diff --git a/kioslave/media/mediamanager/tdehardwarebackend.cpp b/kioslave/media/mediamanager/tdehardwarebackend.cpp index 7b0315b1a..dc615a146 100644 --- a/kioslave/media/mediamanager/tdehardwarebackend.cpp +++ b/kioslave/media/mediamanager/tdehardwarebackend.cpp @@ -19,6 +19,7 @@ #include "tdehardwarebackend.h" #include +#include #include #include @@ -140,16 +141,19 @@ void TDEBackend::AddDevice(TDEStorageDevice * sdevice, bool allowNotification) // } else { + // Create medium + Medium* medium = new Medium(sdevice->uniqueID(), ""); + setVolumeProperties(medium); + // Do not list the LUKS backend device if it has been unlocked elsewhere if (sdevice->isDiskOfType(TDEDiskDeviceType::LUKS)) { - if (sdevice->slaveDevices().count() > 0) { - return; + if (sdevice->holdingDevices().count() > 0) { + medium->setHidden(true); + } + else { + medium->setHidden(false); } } - - // Create medium - Medium* medium = new Medium(sdevice->uniqueID(), ""); - setVolumeProperties(medium); // Insert medium into list m_mediaList.addMedium(medium, allowNotification); @@ -186,14 +190,38 @@ void TDEBackend::AddDevice(TDEStorageDevice * sdevice, bool allowNotification) if ((sdevice->checkDiskStatus(TDEDiskDeviceStatus::Removable)) && (!(sdevice->checkDiskStatus(TDEDiskDeviceStatus::Inserted)))) { allowNotification = false; } - // Create medium - Medium* medium = new Medium(sdevice->uniqueID(), ""); - // If the storage has a volume, we ignore it - if ( setFloppyProperties(medium) ) - m_mediaList.addMedium(medium, allowNotification); - else - delete medium; - return; + + /* We only list volumes that... + * - are encrypted with LUKS or + * - have a filesystem or + * - are a floppy disk + */ + if (!(sdevice->isDiskOfType(TDEDiskDeviceType::LUKS)) + && !(sdevice->checkDiskStatus(TDEDiskDeviceStatus::ContainsFilesystem)) + && !(sdevice->isDiskOfType(TDEDiskDeviceType::Floppy)) + && !(sdevice->checkDiskStatus(TDEDiskDeviceStatus::Blank)) + ) { + // + } + else { + // Create medium + Medium* medium = new Medium(sdevice->uniqueID(), ""); + + setFloppyProperties(medium); + + // Do not list the LUKS backend device if it has been unlocked elsewhere + if (sdevice->isDiskOfType(TDEDiskDeviceType::LUKS)) { + if (sdevice->holdingDevices().count() > 0) { + medium->setHidden(true); + } + else { + medium->setHidden(false); + } + } + + m_mediaList.addMedium(medium, allowNotification); + return; + } } // PTP camera @@ -213,26 +241,37 @@ void TDEBackend::AddDevice(TDEStorageDevice * sdevice, bool allowNotification) void TDEBackend::RemoveDevice(TDEStorageDevice * sdevice) { - const Medium *medium = m_mediaList.findByClearUdi(sdevice->uniqueID()); - if (medium) { - ResetProperties(sdevice); - } - else { - m_mediaList.removeMedium(sdevice->uniqueID(), true); + if (!m_mediaList.findById(sdevice->uniqueID())) { + return; } + + m_mediaList.removeMedium(sdevice->uniqueID(), true); } void TDEBackend::ModifyDevice(TDEStorageDevice * sdevice) { bool allowNotification = true; - if (!sdevice->checkDiskStatus(TDEDiskDeviceStatus::Removable)) { // TODO Is this the only condition under which we would not want notification? - allowNotification = false; - } +// if (!sdevice->checkDiskStatus(TDEDiskDeviceStatus::Removable)) { // FIXME Under which conditions would we not want notification? +// allowNotification = false; +// } ResetProperties(sdevice, allowNotification); } -void TDEBackend::ResetProperties(TDEStorageDevice * sdevice, bool allowNotification) +void TDEBackend::ResetProperties(TDEStorageDevice * sdevice, bool allowNotification, bool overrideIgnoreList) { + if (!m_mediaList.findById(sdevice->uniqueID())) { + // This device is not currently in the device list, so add it and exit + AddDevice(sdevice, allowNotification); + return; + } + + // If we should ignore device change events for this device, do so + if (overrideIgnoreList == false) { + if (m_ignoreDeviceChangeEvents.contains(sdevice->uniqueID())) { + return; + } + } + Medium* m = new Medium(sdevice->uniqueID(), ""); // Keep these conditions in sync with ::AddDevice above, OR ELSE!!! @@ -245,11 +284,13 @@ void TDEBackend::ResetProperties(TDEStorageDevice * sdevice, bool allowNotificat ) { } else { + // Do not list the LUKS backend device if it has been unlocked elsewhere if (sdevice->isDiskOfType(TDEDiskDeviceType::LUKS)) { - if (sdevice->slaveDevices().count() > 0) { - // Do not list the LUKS backend device if it has been unlocked elsewhere - RemoveDevice(sdevice); - return; + if (sdevice->holdingDevices().count() > 0) { + m->setHidden(true); + } + else { + m->setHidden(false); } } setVolumeProperties(m); @@ -275,7 +316,27 @@ void TDEBackend::ResetProperties(TDEStorageDevice * sdevice, bool allowNotificat (sdevice->isDiskOfType(TDEDiskDeviceType::Zip)) || (sdevice->isDiskOfType(TDEDiskDeviceType::Jaz)) ) { - setFloppyProperties(m); + + if (!(sdevice->isDiskOfType(TDEDiskDeviceType::LUKS)) + && !(sdevice->checkDiskStatus(TDEDiskDeviceStatus::ContainsFilesystem)) + && !(sdevice->isDiskOfType(TDEDiskDeviceType::Floppy)) + && !(sdevice->checkDiskStatus(TDEDiskDeviceStatus::Blank)) + ) { + // + } + else { + // Do not list the LUKS backend device if it has been unlocked elsewhere + if (sdevice->isDiskOfType(TDEDiskDeviceType::LUKS)) { + if (sdevice->holdingDevices().count() > 0) { + m->setHidden(true); + } + else { + m->setHidden(false); + } + } + + setFloppyProperties(m); + } } if (sdevice->isDiskOfType(TDEDiskDeviceType::Camera)) { @@ -446,6 +507,15 @@ void TDEBackend::setVolumeProperties(Medium* medium) } } + if (!medium->needMounting()) { + if (sdevice->isDiskOfType(TDEDiskDeviceType::LUKS)) { + if (sdevice->checkDiskStatus(TDEDiskDeviceStatus::UsedByDevice)) { + // Encrypted base devices must be set to this mimetype or they won't open when the base device node is passed to the kioslave + mimeType = "media/removable_mounted"; + } + } + } + medium->setMimeType(mimeType); } @@ -462,6 +532,22 @@ bool TDEBackend::setFloppyProperties(Medium* medium) medium->setName(generateName(sdevice->deviceNode())); medium->setLabel(i18n("Unknown Drive")); + // Certain disks have a lot in common with hard drives + // FIXME + // Any more? + if ((sdevice->isDiskOfType(TDEDiskDeviceType::Zip)) || (sdevice->isDiskOfType(TDEDiskDeviceType::Jaz))) { + medium->setName(generateName(sdevice->deviceNode())); + if ((sdevice->isDiskOfType(TDEDiskDeviceType::LUKS)) || (sdevice->isDiskOfType(TDEDiskDeviceType::UnlockedCrypt))) { + medium->setEncrypted(true); + } + else { + medium->setEncrypted(false); + } + + // USAGE: mountableState(Device node, Mount point, Filesystem type, Mounted ?) + medium->mountableState(sdevice->deviceNode(), sdevice->mountPath(), sdevice->fileSystemName(), !sdevice->mountPath().isNull()); + } + if (sdevice->isDiskOfType(TDEDiskDeviceType::Floppy)) { if (sdevice->mountPath().isNull()) { medium->setMimeType("media/floppy_unmounted"); @@ -479,7 +565,13 @@ bool TDEBackend::setFloppyProperties(Medium* medium) else { medium->setMimeType("media/zip_mounted" ); } - medium->setLabel(i18n("Zip Drive")); + + // Set label + TQString diskLabel = sdevice->diskLabel(); + if (diskLabel.isNull()) { + diskLabel = i18n("%1 Zip Disk").arg(sdevice->deviceFriendlySize()); + } + medium->setLabel(diskLabel); } /** @todo Mimetype for JAZ drives ? */ @@ -662,18 +754,41 @@ TQString TDEBackend::mount(const Medium *medium) while (m_decryptPasswordValid == false) { tqApp->processEvents(); } - + m_decryptDialog->setEnabled(false); - + tqApp->processEvents(); + if (m_decryptionPassword.isNull()) { delete m_decryptDialog; return TQString("Decryption aborted"); } else { + // Just for some added fun, if udev emits a medium change event, which I then forward, with mounted==0, it stops the MediaProtocol::listDir method dead in its tracks, + // and therefore the media:/ kioslave won't refresh after the encrypted device mount + // Therefore, I need to ignore all change events on this device during the mount process and hope nothing bad happens as a result! + if (!m_ignoreDeviceChangeEvents.contains(sdevice->uniqueID())) { + m_ignoreDeviceChangeEvents.append(sdevice->uniqueID()); + } + // mount encrypted volume with password int mountRetcode; TQString mountMessages; TQString mountedPath = sdevice->mountEncryptedDevice(m_decryptionPassword, diskLabel, optionString, &mountMessages, &mountRetcode); + if (mountedPath.isNull()) { + if (mountRetcode == 0) { + // Mounting was successful + // Because the TDE hardware backend is event driven it might take a little while for the new unencrypted mapped device to show up + // Wait up to 30 seconds for it to appear... + for (int i=0;i<300;i++) { + mountedPath = sdevice->mountPath(); + if (!mountedPath.isNull()) { + break; + } + tqApp->processEvents(50); + usleep(50000); + } + } + } if (mountedPath.isNull()) { if (mountRetcode == 25600) { // Probable LUKS failure @@ -700,29 +815,16 @@ TQString TDEBackend::mount(const Medium *medium) } } - // FIXME - // Handle encrypted devices - -// qerror = mount_priv(medium->id().latin1(), mount_point.utf8(), options, noptions, dbus_connection); -// } else { -// // see if we have a clear volume -// LibHalVolume* halVolume = libhal_volume_from_udi(m_halContext, medium->id().latin1()); -// if (halVolume) { -// char* clearUdi = libhal_volume_crypto_get_clear_volume_udi(m_halContext, halVolume); -// if (clearUdi != NULL) { -// qerror = mount_priv(clearUdi, mount_point.utf8(), options, noptions, dbus_connection); -// libhal_free_string(clearUdi); -// } -// libhal_volume_free(halVolume); -// } -// } - if (!qerror.isEmpty()) { return qerror; } - ResetProperties(sdevice); - + ResetProperties(sdevice, false, true); + + if (m_ignoreDeviceChangeEvents.contains(sdevice->uniqueID())) { + m_ignoreDeviceChangeEvents.remove(sdevice->uniqueID()); + } + return TQString(); } @@ -776,6 +878,10 @@ TQString TDEBackend::unmount(const TQString &_udi) TQString qerror; TQString origqerror; + // Save these for later + TQString uid = sdevice->uniqueID(); + TQString node = sdevice->deviceNode(); + TQString unmountMessages; int unmountRetcode = 0; if (!sdevice->unmountDevice(&unmountMessages, &unmountRetcode)) { @@ -815,7 +921,30 @@ TQString TDEBackend::unmount(const TQString &_udi) return qerror; } - ResetProperties(sdevice); + // There is a possibility that the storage device was unceremoniously removed from the system immediately after it was unmounted + // There is no reliable way to know if this happened either! + // For now, see if the device node still exists + TQFileInfo checkDN(node); + if (!checkDN.exists()) { + m_mediaList.removeMedium(uid, true); + } + else { + TQString mountedPath = sdevice->mountPath(); + if (!mountedPath.isNull()) { + // Because the TDE hardware backend is event driven it might take a little while for the device to show up as unmounted + // Wait up to 30 seconds for the mount to disappear... + for (int i=0;i<300;i++) { + mountedPath = sdevice->mountPath(); + if (mountedPath.isNull()) { + break; + } + tqApp->processEvents(50); + usleep(50000); + } + } + + ResetProperties(sdevice, false); + } return TQString(); } diff --git a/kioslave/media/mediamanager/tdehardwarebackend.h b/kioslave/media/mediamanager/tdehardwarebackend.h index 40181b062..a794fd0fb 100644 --- a/kioslave/media/mediamanager/tdehardwarebackend.h +++ b/kioslave/media/mediamanager/tdehardwarebackend.h @@ -115,8 +115,10 @@ private: * Reset properties for the given medium * * @param sdevice A pointer to a TDEStorageDevice objec + * @param allowNotification Indicates if this event will be notified to the user + * @param overrideIgnoreList If true, override event ignore requests for the current device node */ - void ResetProperties(TDEStorageDevice * sdevice, bool allowNotification=false); + void ResetProperties(TDEStorageDevice * sdevice, bool allowNotification=false, bool overrideIgnoreList=false); /** * Find the medium that is concerned with device udi @@ -160,6 +162,8 @@ private: }; TQMap mount_jobs; + + TQStringList m_ignoreDeviceChangeEvents; }; #endif /* _TDEBACKEND_H_ */