summaryrefslogtreecommitdiffstats
path: root/kioslave/media/mediamanager
diff options
context:
space:
mode:
Diffstat (limited to 'kioslave/media/mediamanager')
-rw-r--r--kioslave/media/mediamanager/halbackend.cpp505
-rw-r--r--kioslave/media/mediamanager/halbackend.h3
-rw-r--r--kioslave/media/mediamanager/medialist.cpp15
-rw-r--r--kioslave/media/mediamanager/medialist.h1
-rw-r--r--kioslave/media/mediamanager/mediamanager.cpp22
-rw-r--r--kioslave/media/mediamanager/mediamanager.h2
6 files changed, 516 insertions, 32 deletions
diff --git a/kioslave/media/mediamanager/halbackend.cpp b/kioslave/media/mediamanager/halbackend.cpp
index 65c796605..4d6d9b19d 100644
--- a/kioslave/media/mediamanager/halbackend.cpp
+++ b/kioslave/media/mediamanager/halbackend.cpp
@@ -20,8 +20,10 @@
#include "linuxcdpolling.h"
#include <stdlib.h>
+#include <locale.h>
#include <kapplication.h>
+#include <kmessagebox.h>
#include <qeventloop.h>
#include <qfile.h>
#include <klocale.h>
@@ -33,9 +35,17 @@
#include <kmountpoint.h>
#include <kmessagebox.h>
#include <kio/job.h>
+#include <kstandarddirs.h>
+#include <kprocess.h>
-#define MOUNT_SUFFIX (libhal_volume_is_mounted(halVolume) ? QString("_mounted") : QString("_unmounted"))
-#define MOUNT_ICON_SUFFIX (libhal_volume_is_mounted(halVolume) ? QString("_mount") : QString("_unmount"))
+#define MOUNT_SUFFIX ( \
+ (medium->isMounted() ? QString("_mounted") : QString("_unmounted")) + \
+ (medium->isEncrypted() ? (halClearVolume ? "_decrypted" : "_encrypted") : "" ) \
+ )
+#define MOUNT_ICON_SUFFIX ( \
+ (medium->isMounted() ? QString("_mount") : QString("_unmount")) + \
+ (medium->isEncrypted() ? (halClearVolume ? "_decrypt" : "_encrypt") : "" ) \
+ )
/* Static instance of this class, for static HAL callbacks */
static HALBackend* s_HALBackend;
@@ -211,8 +221,15 @@ void HALBackend::AddDevice(const char *udi, bool allowNotification)
/* Add volume block devices */
if (libhal_device_query_capability(m_halContext, udi, "volume", NULL))
{
- /* We only list volume that have a filesystem or volume that have an audio track*/
- if ( libhal_device_get_property_QString(m_halContext, udi, "volume.fsusage") != "filesystem" &&
+ /* We only list volumes that...
+ * - are encrypted with LUKS or
+ * - have a filesystem or
+ * - have an audio track
+ */
+ if ( ( libhal_device_get_property_QString(m_halContext, udi, "volume.fsusage") != "crypto" ||
+ libhal_device_get_property_QString(m_halContext, udi, "volume.fstype") != "crypto_LUKS"
+ ) &&
+ libhal_device_get_property_QString(m_halContext, udi, "volume.fsusage") != "filesystem" &&
!libhal_device_get_property_bool(m_halContext, udi, "volume.disc.has_audio", NULL) &&
!libhal_device_get_property_bool(m_halContext, udi, "volume.disc.is_blank", NULL) )
return;
@@ -232,6 +249,21 @@ void HALBackend::AddDevice(const char *udi, bool allowNotification)
/** @todo check exclusion list **/
+ /* Special handling for clear crypto volumes */
+ LibHalVolume* halVolume = libhal_volume_from_udi(m_halContext, udi);
+ if (!halVolume)
+ return;
+ const char* backingVolumeUdi = libhal_volume_crypto_get_backing_volume_udi(halVolume);
+ if ( backingVolumeUdi != NULL )
+ {
+ /* The crypto drive was unlocked and may now be mounted... */
+ kdDebug(1219) << "HALBackend::AddDevice : ClearVolume appeared for " << backingVolumeUdi << endl;
+ ResetProperties(backingVolumeUdi, allowNotification);
+ libhal_volume_free(halVolume);
+ return;
+ }
+ libhal_volume_free(halVolume);
+
/* Create medium */
Medium* medium = new Medium(udi, "");
setVolumeProperties(medium);
@@ -247,6 +279,11 @@ void HALBackend::AddDevice(const char *udi, bool allowNotification)
return;
}
}
+
+ // instert medium into list
+ m_mediaList.addMedium(medium, allowNotification);
+
+ // finally check for automount
QMap<QString,QString> options = MediaManagerUtils::splitOptions(mountoptions(udi));
kdDebug() << "automount " << options["automount"] << endl;
if (options["automount"] == "true" && allowNotification ) {
@@ -254,7 +291,6 @@ void HALBackend::AddDevice(const char *udi, bool allowNotification)
if (!error.isEmpty())
kdDebug() << "error " << error << endl;
}
- m_mediaList.addMedium(medium, allowNotification);
return;
}
@@ -295,11 +331,18 @@ void HALBackend::AddDevice(const char *udi, bool allowNotification)
void HALBackend::RemoveDevice(const char *udi)
{
- m_mediaList.removeMedium(udi, true);
+ const Medium *medium = m_mediaList.findByClearUdi(udi);
+ if (medium) {
+ ResetProperties(medium->id().ascii());
+ } else {
+ m_mediaList.removeMedium(udi, true);
+ }
}
void HALBackend::ModifyDevice(const char *udi, const char* key)
{
+ kdDebug(1219) << "HALBackend::ModifyDevice for '" << udi << "' on '" << key << "'\n";
+
const char* mediumUdi = findMediumUdiFromUdi(udi);
if (!mediumUdi)
return;
@@ -381,6 +424,18 @@ const char* HALBackend::findMediumUdiFromUdi(const char* udi)
if (libhal_device_property_exists(m_halContext, udi, "info.capabilities", NULL))
if (libhal_device_query_capability(m_halContext, udi, "volume", NULL))
{
+ /* check if this belongs to an encrypted volume */
+ LibHalVolume* halVolume = libhal_volume_from_udi(m_halContext, udi);
+ if (!halVolume) return NULL;
+ const char* backingUdi = libhal_volume_crypto_get_backing_volume_udi(halVolume);
+ if (backingUdi != NULL) {
+ const char* result = findMediumUdiFromUdi(backingUdi);
+ libhal_volume_free(halVolume);
+ return result;
+ }
+ libhal_volume_free(halVolume);
+
+ /* this is a volume whose drive is registered */
QString driveUdi = libhal_device_get_property_QString(m_halContext, udi, "block.storage_device");
return findMediumUdiFromUdi(driveUdi.ascii());
}
@@ -445,11 +500,47 @@ void HALBackend::setVolumeProperties(Medium* medium)
medium->setName(
generateName(libhal_volume_get_device_file(halVolume)) );
- medium->mountableState(
- libhal_volume_get_device_file(halVolume), /* Device node */
- libhal_volume_get_mount_point(halVolume), /* Mount point */
- libhal_volume_get_fstype(halVolume), /* Filesystem type */
- libhal_volume_is_mounted(halVolume) ); /* Mounted ? */
+ LibHalVolume* halClearVolume = NULL;
+ if ( libhal_device_get_property_QString(m_halContext, udi, "volume.fsusage") == "crypto" )
+ {
+ kdDebug(1219) << "HALBackend::setVolumeProperties : crypto volume" << endl;
+
+ medium->setEncrypted(true);
+ char* clearUdi = libhal_volume_crypto_get_clear_volume_udi(m_halContext, halVolume);
+ QString clearUdiString;
+ if (clearUdi != NULL) {
+ kdDebug(1219) << "HALBackend::setVolumeProperties : crypto clear volume avail - " << clearUdi << endl;
+ halClearVolume = libhal_volume_from_udi(m_halContext, clearUdi);
+ // ignore if halClearVolume is NULL -> just not decrypted in this case
+ clearUdiString = clearUdi;
+ libhal_free_string(clearUdi);
+ }
+
+ if (halClearVolume)
+ medium->mountableState(
+ libhal_volume_get_device_file(halVolume), /* Device node */
+ clearUdiString,
+ libhal_volume_get_mount_point(halClearVolume), /* Mount point */
+ libhal_volume_get_fstype(halClearVolume), /* Filesystem type */
+ libhal_volume_is_mounted(halClearVolume) ); /* Mounted ? */
+ else
+ medium->mountableState(
+ libhal_volume_get_device_file(halVolume), /* Device node */
+ QString::null,
+ QString::null, /* Mount point */
+ QString::null, /* Filesystem type */
+ false ); /* Mounted ? */
+ }
+ else
+ {
+ kdDebug(1219) << "HALBackend::setVolumeProperties : normal volume" << endl;
+ medium->mountableState(
+ libhal_volume_get_device_file(halVolume), /* Device node */
+ libhal_volume_get_mount_point(halVolume), /* Mount point */
+ libhal_volume_get_fstype(halVolume), /* Filesystem type */
+ libhal_volume_is_mounted(halVolume) ); /* Mounted ? */
+ }
+
char* name = libhal_volume_policy_compute_display_name(halDrive, halVolume, m_halStoragePolicy);
QString volume_name = QString::fromUtf8(name);
@@ -777,13 +868,35 @@ void HALBackend::hal_device_condition(LibHalContext *ctx, const char *udi,
QStringList HALBackend::mountoptions(const QString &name)
{
const Medium* medium = m_mediaList.findById(name);
- if (medium && !isInFstab(medium).isNull())
+ if (!medium)
+ return QStringList(); // we don't know about that one
+ if (!isInFstab(medium).isNull())
return QStringList(); // not handled by HAL - fstab entry
+ QString volume_udi = name;
+ if (medium->isEncrypted()) {
+ // 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) {
+ volume_udi = clearUdi;
+ libhal_free_string(clearUdi);
+ } else {
+ // if not decrypted yet then no mountoptions
+ return QStringList();
+ }
+ libhal_volume_free(halVolume);
+ } else {
+ // strange...
+ return QStringList();
+ }
+ }
+
KConfig config("mediamanagerrc");
config.setGroup(name);
- char ** array = libhal_device_get_property_strlist(m_halContext, name.latin1(), "volume.mount.valid_options", NULL);
+ char ** array = libhal_device_get_property_strlist(m_halContext, volume_udi.latin1(), "volume.mount.valid_options", NULL);
QMap<QString,bool> valids;
for (int index = 0; array && array[index]; ++index) {
@@ -797,11 +910,11 @@ QStringList HALBackend::mountoptions(const QString &name)
QStringList result;
QString tmp;
- QString fstype = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.fstype");
+ QString fstype = libhal_device_get_property_QString(m_halContext, volume_udi.latin1(), "volume.fstype");
if (fstype.isNull())
- fstype = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.policy.mount_filesystem");
+ fstype = libhal_device_get_property_QString(m_halContext, volume_udi.latin1(), "volume.policy.mount_filesystem");
- QString drive_udi = libhal_device_get_property_QString(m_halContext, name.latin1(), "block.storage_device");
+ QString drive_udi = libhal_device_get_property_QString(m_halContext, volume_udi.latin1(), "block.storage_device");
bool removable = false;
if ( !drive_udi.isNull() )
@@ -812,11 +925,11 @@ QStringList HALBackend::mountoptions(const QString &name)
bool value = config.readBoolEntry("automount", false);
config.setGroup(name);
- if (libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_blank", NULL)
- || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_vcd", NULL)
- || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_svcd", NULL)
- || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_videodvd", NULL)
- || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.has_audio", NULL))
+ if (libhal_device_get_property_bool(m_halContext, volume_udi.latin1(), "volume.disc.is_blank", NULL)
+ || libhal_device_get_property_bool(m_halContext, volume_udi.latin1(), "volume.disc.is_vcd", NULL)
+ || libhal_device_get_property_bool(m_halContext, volume_udi.latin1(), "volume.disc.is_svcd", NULL)
+ || libhal_device_get_property_bool(m_halContext, volume_udi.latin1(), "volume.disc.is_videodvd", NULL)
+ || libhal_device_get_property_bool(m_halContext, volume_udi.latin1(), "volume.disc.has_audio", NULL))
value = false;
result << QString("automount=%1").arg(value ? "true" : "false");
@@ -898,9 +1011,9 @@ QStringList HALBackend::mountoptions(const QString &name)
result << tmp;
}
- QString mount_point = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.mount_point");
+ QString mount_point = libhal_device_get_property_QString(m_halContext, volume_udi.latin1(), "volume.mount_point");
if (mount_point.isEmpty())
- mount_point = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.policy.desired_mount_point");
+ mount_point = libhal_device_get_property_QString(m_halContext, volume_udi.latin1(), "volume.policy.desired_mount_point");
mount_point = config.readEntry("mountpoint", mount_point);
@@ -958,6 +1071,120 @@ bool HALBackend::setMountoptions(const QString &name, const QStringList &options
return true;
}
+QString startKdeSudoProcess(const QString& kdesudoPath, const QString& command,
+ const QString& dialogCaption, const QString& dialogComment)
+{
+ KProcess kdesudoProcess;
+
+ kdesudoProcess << kdesudoPath
+ << "-d"
+ << "--noignorebutton"
+ << "--caption" << dialogCaption
+ << "--comment" << dialogComment
+ << "-c" << command;
+
+ // @todo handle kdesudo output
+ kdesudoProcess.start(KProcess::Block);
+
+ return QString();
+}
+
+QString startKdeSuProcess(const QString& kdesuPath, const QString& command,
+ const QString& dialogCaption)
+{
+ KProcess kdesuProcess;
+
+ kdesuProcess << kdesuPath
+ << "-d"
+ << "--noignorebutton"
+ << "--caption" << dialogCaption
+ << "-c" << command;
+
+ // @todo handle kdesu output
+ kdesuProcess.start(KProcess::Block);
+
+ return QString();
+}
+
+QString startPrivilegedProcess(const QString& command, const QString& dialogCaption, const QString& dialogComment)
+{
+ QString error;
+
+ QString kdesudoPath = KStandardDirs::findExe("kdesudo");
+
+ if (!kdesudoPath.isEmpty())
+ error = startKdeSudoProcess(kdesudoPath, command, dialogCaption, dialogComment);
+ else {
+ QString kdesuPath = KStandardDirs::findExe("kdesu");
+
+ if (!kdesuPath.isEmpty())
+ error = startKdeSuProcess(kdesuPath, command, dialogCaption);
+ }
+
+ return error;
+}
+
+QString privilegedMount(const char* udi, const char* mountPoint, const char** options, int numberOfOptions)
+{
+ QString error;
+
+ kdDebug() << "run privileged mount for " << udi << endl;
+
+ QString dbusSendPath = KStandardDirs::findExe("dbus-send");
+
+ // @todo return error message
+ if (dbusSendPath.isEmpty())
+ return QString();
+
+ QString mountOptions;
+ QTextOStream optionsStream(&mountOptions);
+ for (int optionIndex = 0; optionIndex < numberOfOptions; optionIndex++) {
+ optionsStream << options[optionIndex];
+ if (optionIndex < numberOfOptions - 1)
+ optionsStream << ",";
+ }
+
+ QString command;
+ QTextOStream(&command) << dbusSendPath
+ << " --system --print-reply --dest=org.freedesktop.Hal " << udi
+ << " org.freedesktop.Hal.Device.Volume.Mount string:" << mountPoint
+ << " string: array:string:" << mountOptions;
+
+ kdDebug() << "command: " << command << endl;
+
+ error = startPrivilegedProcess(command,
+ i18n("Authenticate"),
+ i18n("<big><b>System policy prevents mounting internal media</b></big><br/>Authentication is required to perform this action. Please enter your password to verify."));
+
+ return error;
+}
+
+QString privilegedUnmount(const char* udi)
+{
+ QString error;
+
+ kdDebug() << "run privileged unmount for " << udi << endl;
+
+ QString dbusSendPath = KStandardDirs::findExe("dbus-send");
+
+ // @todo return error message
+ if (dbusSendPath.isEmpty())
+ return QString();
+
+ QString command;
+ QTextOStream(&command) << dbusSendPath
+ << " --system --print-reply --dest=org.freedesktop.Hal " << udi
+ << " org.freedesktop.Hal.Device.Volume.Unmount array:string:force";
+
+ kdDebug() << "command: " << command << endl;
+
+ error = startPrivilegedProcess(command,
+ i18n("Authenticate"),
+ i18n("<big><b>System policy prevents unmounting media mounted by other users</b></big><br/>Authentication is required to perform this action. Please enter your password to verify."));
+
+ return error;
+}
+
static QString mount_priv(const char *udi, const char *mount_point, const char **poptions, int noptions,
DBusConnection *dbus_connection)
{
@@ -992,6 +1219,8 @@ static QString mount_priv(const char *udi, const char *mount_point, const char *
qerror = i18n("Invalid filesystem type");
else if ( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.PermissionDenied"))
qerror = i18n("Permissions denied");
+ else if ( !strcmp(error.name, "org.freedesktop.Hal.Device.PermissionDeniedByPolicy"))
+ qerror = privilegedMount(udi, mount_point, poptions, noptions);
else if ( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.AlreadyMounted"))
qerror = i18n("Device is already mounted.");
else if ( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.InvalidMountpoint") && strlen(mount_point)) {
@@ -1050,6 +1279,41 @@ QString HALBackend::listUsingProcesses(const Medium* medium)
}
}
+QString HALBackend::killUsingProcesses(const Medium* medium)
+{
+ QString proclist, fullmsg;
+ QString cmdline = QString("/usr/bin/env fuser -vmk %1 2>&1").arg(KProcess::quote(medium->mountPoint()));
+ FILE *fuser = popen(cmdline.latin1(), "r");
+
+ uint counter = 0;
+ if (fuser) {
+ proclist += "<pre>";
+ QTextIStream is(fuser);
+ QString tmp;
+ while (!is.atEnd()) {
+ tmp = is.readLine();
+ tmp = QStyleSheet::escape(tmp) + "\n";
+
+ proclist += tmp;
+ if (counter++ > 10)
+ {
+ proclist += "...";
+ break;
+ }
+ }
+ proclist += "</pre>";
+ (void)pclose( fuser );
+ }
+ if (counter) {
+ fullmsg = i18n("Programs that were still using the device "
+ "have been forcibly terminated. They are listed below.");
+ fullmsg += "<br>" + proclist;
+ return fullmsg;
+ } else {
+ return QString::null;
+ }
+}
+
void HALBackend::slotResult(KIO::Job *job)
{
kdDebug() << "slotResult " << mount_jobs[job] << endl;
@@ -1148,7 +1412,7 @@ QString HALBackend::mount(const Medium *medium)
if (valids["flush"] == "true")
soptions << "flush";
- if (valids["uid"] == "true")
+ if ((valids["uid"] == "true") && (medium->fsType() != "ntfs"))
{
soptions << QString("uid=%1").arg(getuid());
}
@@ -1168,6 +1432,13 @@ QString HALBackend::mount(const Medium *medium)
if (valids["sync"] == "true")
soptions << "sync";
+ if (medium->fsType() == "ntfs") {
+ QString fsLocale("locale=");
+ fsLocale += setlocale(LC_ALL, "");
+
+ soptions << fsLocale;
+ }
+
QString mount_point = valids["mountpoint"];
if (mount_point.startsWith("/media/"))
mount_point = mount_point.mid(7);
@@ -1199,7 +1470,24 @@ QString HALBackend::mount(const Medium *medium)
options[noptions] = (*it).latin1();
options[noptions] = NULL;
- QString qerror = mount_priv(medium->id().latin1(), mount_point.utf8(), options, noptions, dbus_connection);
+ QString qerror = i18n("Cannot mount encrypted drives!");
+
+ if (!medium->isEncrypted()) {
+ // normal volume
+ 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()) {
kdError() << "mounting " << medium->id() << " returned " << qerror << endl;
return qerror;
@@ -1266,8 +1554,26 @@ QString HALBackend::unmount(const QString &_udi)
DBusMessage *dmesg, *reply;
DBusError error;
const char *options[2];
+ QString udi = QString::null;
+
+ if (!medium->isEncrypted()) {
+ // normal volume
+ udi = medium->id();
+ } 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);
+ udi = clearUdi;
+ libhal_free_string(clearUdi);
+ libhal_volume_free(halVolume);
+ }
+ }
+ if (udi.isNull()) {
+ kdDebug() << "unmount failed: no udi" << endl;
+ return i18n("Internal Error");
+ }
- const char *udi = medium->id().latin1();
kdDebug() << "unmounting " << udi << "..." << endl;
dbus_error_init(&error);
@@ -1278,7 +1584,7 @@ QString HALBackend::unmount(const QString &_udi)
return false;
}
- if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
+ if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.Hal", udi.latin1(),
"org.freedesktop.Hal.Device.Volume",
"Unmount"))) {
kdDebug() << "unmount failed for " << udi << ": could not create dbus message\n";
@@ -1296,11 +1602,25 @@ QString HALBackend::unmount(const QString &_udi)
return i18n("Internal Error");
}
+ char thisunmounthasfailed = 0;
dbus_error_init (&error);
if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error)))
{
- QString qerror, reason;
+ thisunmounthasfailed = 1;
+ QString qerror, reason, origqerror;
+ if (!strcmp(error.name, "org.freedesktop.Hal.Device.PermissionDeniedByPolicy")) {
+ qerror = privilegedUnmount(udi.latin1());
+
+ if (qerror.isEmpty()) {
+ dbus_message_unref(dmesg);
+ dbus_error_free(&error);
+ return QString();
+ }
+
+ // @todo handle unmount error message
+ }
+
kdDebug() << "unmount failed for " << udi << ": " << error.name << " " << error.message << endl;
qerror = "<qt>";
qerror += "<p>" + i18n("Unfortunately, the device <b>%1</b> (%2) named <b>'%3'</b> and "
@@ -1312,6 +1632,7 @@ QString HALBackend::unmount(const QString &_udi)
qerror += "<p>" + i18n("Unmounting failed due to the following error:") + "</p>";
if (!strcmp(error.name, "org.freedesktop.Hal.Device.Volume.Busy")) {
reason = i18n("Device is Busy:");
+ thisunmounthasfailed = 2;
} else if (!strcmp(error.name, "org.freedesktop.Hal.Device.Volume.NotMounted")) {
// this is faking. The error is that the device wasn't mounted by hal (but by the system)
reason = i18n("Permissions denied");
@@ -1319,16 +1640,29 @@ QString HALBackend::unmount(const QString &_udi)
reason = error.message;
}
qerror += "<p><b>" + reason + "</b></p>";
+ origqerror = qerror;
// Include list of processes (if any) using the device in the error message
reason = listUsingProcesses(medium);
if (!reason.isEmpty()) {
qerror += reason;
+ if (thisunmounthasfailed == 2) { // Failed as BUSY
+ if (KMessageBox::warningYesNo(0, i18n("%1<p><b>Would you like to forcibly terminate these processes?</b><br><i>All unsaved data would be lost</i>").arg(qerror)) == KMessageBox::Yes) {
+ qerror = origqerror;
+ reason = killUsingProcesses(medium);
+ qerror = HALBackend::unmount(udi);
+ if (qerror.isNull()) {
+ thisunmounthasfailed = 0;
+ }
+ }
+ }
}
- dbus_message_unref (dmesg);
- dbus_error_free (&error);
- return qerror;
+ if (thisunmounthasfailed != 0) {
+ dbus_message_unref (dmesg);
+ dbus_error_free (&error);
+ return qerror;
+ }
}
kdDebug() << "unmount queued for " << udi << endl;
@@ -1337,8 +1671,117 @@ QString HALBackend::unmount(const QString &_udi)
dbus_message_unref (reply);
medium->setHalMounted(false);
+ ResetProperties(medium->id().latin1());
+
+ while (dbus_connection_dispatch(dbus_connection) == DBUS_DISPATCH_DATA_REMAINS) ;
+
+ return QString();
+}
+
+QString HALBackend::decrypt(const QString &_udi, const QString &password)
+{
+ const Medium* medium = m_mediaList.findById(_udi);
+ if (!medium)
+ return i18n("No such medium: %1").arg(_udi);
+
+ if (!medium->isEncrypted() || !medium->clearDeviceUdi().isNull())
+ return QString();
+
+ const char *udi = medium->id().latin1();
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError error;
+
+ kdDebug() << "Setting up " << udi << " for crypto\n" <<endl;
+
+ msg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
+ "org.freedesktop.Hal.Device.Volume.Crypto",
+ "Setup");
+ if (msg == NULL) {
+ kdDebug() << "decrypt failed for " << udi << ": could not create dbus message\n";
+ return i18n("Internal Error");
+ }
+
+ QCString pwdUtf8 = password.utf8();
+ const char *pwd_utf8 = pwdUtf8;
+ if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &pwd_utf8, DBUS_TYPE_INVALID)) {
+ kdDebug() << "decrypt failed for " << udi << ": could not append args to dbus message\n";
+ dbus_message_unref (msg);
+ return i18n("Internal Error");
+ }
+
+ dbus_error_init (&error);
+ if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, msg, -1, &error)) ||
+ dbus_error_is_set (&error))
+ {
+ QString qerror = i18n("Internal Error");
+ kdDebug() << "decrypt failed for " << udi << ": " << error.name << " " << error.message << endl;
+ if (strcmp (error.name, "org.freedesktop.Hal.Device.Volume.Crypto.SetupPasswordError") == 0) {
+ qerror = i18n("Wrong password");
+ }
+ dbus_error_free (&error);
+ dbus_message_unref (msg);
+ while (dbus_connection_dispatch(dbus_connection) == DBUS_DISPATCH_DATA_REMAINS) ;
+ return qerror;
+ }
+
+ dbus_message_unref (msg);
+ dbus_message_unref (reply);
+
+ while (dbus_connection_dispatch(dbus_connection) == DBUS_DISPATCH_DATA_REMAINS) ;
+
+ return QString();
+}
+
+QString HALBackend::undecrypt(const QString &_udi)
+{
+ const Medium* medium = m_mediaList.findById(_udi);
+ if (!medium)
+ return i18n("No such medium: %1").arg(_udi);
+
+ if (!medium->isEncrypted() || medium->clearDeviceUdi().isNull())
+ return QString();
+
+ const char *udi = medium->id().latin1();
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError error;
+
+ kdDebug() << "Tear down " << udi << "\n" <<endl;
+
+ msg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
+ "org.freedesktop.Hal.Device.Volume.Crypto",
+ "Teardown");
+ if (msg == NULL) {
+ kdDebug() << "teardown failed for " << udi << ": could not create dbus message\n";
+ return i18n("Internal Error");
+ }
+
+ if (!dbus_message_append_args (msg, DBUS_TYPE_INVALID)) {
+ kdDebug() << "teardown failed for " << udi << ": could not append args to dbus message\n";
+ dbus_message_unref (msg);
+ return i18n("Internal Error");
+ }
+
+ dbus_error_init (&error);
+ if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, msg, -1, &error)) ||
+ dbus_error_is_set (&error))
+ {
+ QString qerror = i18n("Internal Error");
+ kdDebug() << "teardown failed for " << udi << ": " << error.name << " " << error.message << endl;
+ dbus_error_free (&error);
+ dbus_message_unref (msg);
+ while (dbus_connection_dispatch(dbus_connection) == DBUS_DISPATCH_DATA_REMAINS) ;
+ return qerror;
+ }
+
+ dbus_message_unref (msg);
+ dbus_message_unref (reply);
+
ResetProperties(udi);
+ while (dbus_connection_dispatch(dbus_connection) == DBUS_DISPATCH_DATA_REMAINS) ;
+
return QString();
}
diff --git a/kioslave/media/mediamanager/halbackend.h b/kioslave/media/mediamanager/halbackend.h
index 31c682374..c5bdd532c 100644
--- a/kioslave/media/mediamanager/halbackend.h
+++ b/kioslave/media/mediamanager/halbackend.h
@@ -85,6 +85,8 @@ public:
QString mount(const QString &id);
QString mount(const Medium *medium);
QString unmount(const QString &id);
+ QString decrypt(const QString &id, const QString &password);
+ QString undecrypt(const QString &id);
private:
/**
@@ -143,6 +145,7 @@ private:
QString generateName(const QString &devNode);
static QString isInFstab(const Medium *medium);
static QString listUsingProcesses(const Medium *medium);
+ static QString killUsingProcesses(const Medium *medium);
private slots:
void slotResult(KIO::Job *job);
diff --git a/kioslave/media/mediamanager/medialist.cpp b/kioslave/media/mediamanager/medialist.cpp
index fed6091fb..974eddbf6 100644
--- a/kioslave/media/mediamanager/medialist.cpp
+++ b/kioslave/media/mediamanager/medialist.cpp
@@ -52,6 +52,18 @@ const Medium *MediaList::findByName(const QString &name) const
return m_nameMap[name];
}
+const Medium *MediaList::findByClearUdi(const QString &name)
+{
+ kdDebug(1219) << "MediaList::findByClearUdi(" << name << ")" << endl;
+
+ Medium *medium;
+ for (medium = m_media.first(); medium; medium = m_media.next()) {
+ if (medium->clearDeviceUdi() == name) return medium;
+ }
+
+ return 0L;
+}
+
QString MediaList::addMedium(Medium *medium, bool allowNotification)
{
@@ -121,11 +133,12 @@ bool MediaList::changeMediumState(const Medium &medium, bool allowNotification)
if ( medium.isMountable() )
{
QString device_node = medium.deviceNode();
+ QString clear_device_udi = medium.clearDeviceUdi();
QString mount_point = medium.mountPoint();
QString fs_type = medium.fsType();
bool mounted = medium.isMounted();
- m->mountableState( device_node, mount_point,
+ m->mountableState( device_node, clear_device_udi, mount_point,
fs_type, mounted );
}
else
diff --git a/kioslave/media/mediamanager/medialist.h b/kioslave/media/mediamanager/medialist.h
index 590491b0c..4de333875 100644
--- a/kioslave/media/mediamanager/medialist.h
+++ b/kioslave/media/mediamanager/medialist.h
@@ -34,6 +34,7 @@ public:
const QPtrList<Medium> list() const;
const Medium *findById(const QString &id) const;
const Medium *findByName(const QString &name) const;
+ const Medium *findByClearUdi(const QString &name);
public:
QString addMedium(Medium *medium, bool allowNotification = true);
diff --git a/kioslave/media/mediamanager/mediamanager.cpp b/kioslave/media/mediamanager/mediamanager.cpp
index ad8f1b447..f1569e817 100644
--- a/kioslave/media/mediamanager/mediamanager.cpp
+++ b/kioslave/media/mediamanager/mediamanager.cpp
@@ -232,6 +232,28 @@ QString MediaManager::unmount(const QString &name)
#endif
}
+QString MediaManager::decrypt(const QString &name, const QString &password)
+{
+#ifdef COMPILE_HALBACKEND
+ if (!m_halbackend)
+ return i18n("Feature only available with HAL");
+ return m_halbackend->decrypt(name, password);
+#else
+ return i18n("Feature only available with HAL");
+#endif
+}
+
+QString MediaManager::undecrypt(const QString &name)
+{
+#ifdef COMPILE_HALBACKEND
+ if (!m_halbackend)
+ return i18n("Feature only available with HAL");
+ return m_halbackend->undecrypt(name);
+#else
+ return i18n("Feature only available with HAL");
+#endif
+}
+
QString MediaManager::nameForLabel(const QString &label)
{
const QPtrList<Medium> media = m_mediaList.list();
diff --git a/kioslave/media/mediamanager/mediamanager.h b/kioslave/media/mediamanager/mediamanager.h
index 1e5aa1d84..36942362d 100644
--- a/kioslave/media/mediamanager/mediamanager.h
+++ b/kioslave/media/mediamanager/mediamanager.h
@@ -47,6 +47,8 @@ k_dcop:
QString mount(const QString &uid);
QString unmount(const QString &uid);
+ QString decrypt(const QString &uid, const QString &password);
+ QString undecrypt(const QString &uid);
QString nameForLabel(const QString &label);
ASYNC setUserLabel(const QString &name, const QString &label);