2010-07-17 16:22:07 +02:00
|
|
|
/* This file is part of Clementine.
|
2010-11-20 14:27:10 +01:00
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
2010-07-17 16:22:07 +02:00
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2010-07-17 19:18:02 +02:00
|
|
|
#include "config.h"
|
2010-07-17 16:22:07 +02:00
|
|
|
|
2014-02-06 14:48:00 +01:00
|
|
|
#include <memory>
|
|
|
|
|
2010-07-17 19:18:02 +02:00
|
|
|
#include <QFile>
|
2010-07-17 16:22:07 +02:00
|
|
|
#include <QStringList>
|
|
|
|
#include <QtDebug>
|
|
|
|
|
2012-06-08 15:34:00 +02:00
|
|
|
#include "giolister.h"
|
|
|
|
#include "core/logging.h"
|
|
|
|
#include "core/signalchecker.h"
|
|
|
|
|
2014-02-06 14:48:00 +01:00
|
|
|
using std::placeholders::_1;
|
|
|
|
using std::placeholders::_2;
|
|
|
|
using std::placeholders::_3;
|
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
QString GioLister::DeviceInfo::unique_id() const {
|
|
|
|
if (mount)
|
2014-02-07 16:34:20 +01:00
|
|
|
return QString("Gio/%1/%2/%3").arg(mount_uuid, filesystem_type).arg(
|
|
|
|
filesystem_size);
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
return QString("Gio/unmounted/%1").arg((qulonglong)volume.get());
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
bool GioLister::DeviceInfo::is_suitable() const {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!volume) return false; // This excludes smb or ssh mounts
|
2010-09-11 14:29:44 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (drive && !drive_removable) return false; // This excludes internal drives
|
2010-09-11 14:29:44 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (filesystem_type.isEmpty()) return true;
|
2010-09-11 14:29:44 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
return filesystem_type != "udf" && filesystem_type != "smb" &&
|
|
|
|
filesystem_type != "cifs" && filesystem_type != "ssh" &&
|
2010-10-17 22:52:07 +02:00
|
|
|
filesystem_type != "isofs";
|
2010-08-01 14:00:50 +02:00
|
|
|
}
|
|
|
|
|
2010-09-04 14:34:01 +02:00
|
|
|
template <typename T, typename F>
|
2014-02-07 16:34:20 +01:00
|
|
|
void OperationFinished(F f, GObject* object, GAsyncResult* result) {
|
2010-09-04 14:34:01 +02:00
|
|
|
T* obj = reinterpret_cast<T*>(object);
|
2014-02-06 16:49:49 +01:00
|
|
|
GError* error = nullptr;
|
2010-09-04 14:34:01 +02:00
|
|
|
|
|
|
|
f(obj, result, &error);
|
|
|
|
|
|
|
|
if (error) {
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Error) << "Mount/unmount error:" << error->message;
|
2010-09-04 14:34:01 +02:00
|
|
|
g_error_free(error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GioLister::VolumeMountFinished(GObject* object, GAsyncResult* result,
|
|
|
|
gpointer) {
|
|
|
|
OperationFinished<GVolume>(std::bind(g_volume_mount_finish, _1, _2, _3),
|
|
|
|
object, result);
|
2010-09-04 14:34:01 +02:00
|
|
|
}
|
|
|
|
|
2010-07-17 16:22:07 +02:00
|
|
|
void GioLister::Init() {
|
2010-09-11 14:29:44 +02:00
|
|
|
monitor_.reset_without_add(g_volume_monitor_get());
|
2010-07-17 16:22:07 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
// Get existing volumes
|
2010-09-04 14:34:01 +02:00
|
|
|
GList* const volumes = g_volume_monitor_get_volumes(monitor_);
|
2014-02-07 16:34:20 +01:00
|
|
|
for (GList* p = volumes; p; p = p->next) {
|
2010-09-04 14:34:01 +02:00
|
|
|
GVolume* volume = static_cast<GVolume*>(p->data);
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
VolumeAdded(volume);
|
2010-09-04 14:34:01 +02:00
|
|
|
g_object_unref(volume);
|
|
|
|
}
|
2010-09-11 14:29:44 +02:00
|
|
|
g_list_free(volumes);
|
2010-09-04 14:34:01 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
// Get existing mounts
|
2010-09-04 14:34:01 +02:00
|
|
|
GList* const mounts = g_volume_monitor_get_mounts(monitor_);
|
2014-02-07 16:34:20 +01:00
|
|
|
for (GList* p = mounts; p; p = p->next) {
|
2010-09-04 14:34:01 +02:00
|
|
|
GMount* mount = static_cast<GMount*>(p->data);
|
2010-07-17 16:22:07 +02:00
|
|
|
|
|
|
|
MountAdded(mount);
|
|
|
|
g_object_unref(mount);
|
|
|
|
}
|
|
|
|
g_list_free(mounts);
|
|
|
|
|
|
|
|
// Connect signals from the monitor
|
2012-06-08 15:34:00 +02:00
|
|
|
CHECKED_GCONNECT(monitor_, "volume-added", &VolumeAddedCallback, this);
|
|
|
|
CHECKED_GCONNECT(monitor_, "volume-removed", &VolumeRemovedCallback, this);
|
|
|
|
CHECKED_GCONNECT(monitor_, "mount-added", &MountAddedCallback, this);
|
|
|
|
CHECKED_GCONNECT(monitor_, "mount-changed", &MountChangedCallback, this);
|
|
|
|
CHECKED_GCONNECT(monitor_, "mount-removed", &MountRemovedCallback, this);
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QStringList GioLister::DeviceUniqueIDs() {
|
2010-07-17 19:18:02 +02:00
|
|
|
QMutexLocker l(&mutex_);
|
2010-09-11 14:29:44 +02:00
|
|
|
return devices_.keys();
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QVariantList GioLister::DeviceIcons(const QString& id) {
|
2010-08-16 01:26:04 +02:00
|
|
|
QVariantList ret;
|
2010-09-11 14:29:44 +02:00
|
|
|
QMutexLocker l(&mutex_);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!devices_.contains(id)) return ret;
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
const DeviceInfo& info = devices_[id];
|
|
|
|
|
|
|
|
if (info.mount) {
|
|
|
|
ret << DeviceLister::GuessIconForPath(info.mount_path);
|
|
|
|
ret << info.mount_icon_names;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret << DeviceLister::GuessIconForModel(QString(), info.mount_name);
|
|
|
|
|
2010-07-25 02:20:18 +02:00
|
|
|
return ret;
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QString GioLister::DeviceManufacturer(const QString& id) { return QString(); }
|
2010-07-17 16:22:07 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QString GioLister::DeviceModel(const QString& id) {
|
2010-09-11 14:29:44 +02:00
|
|
|
QMutexLocker l(&mutex_);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!devices_.contains(id)) return QString();
|
2010-09-11 14:29:44 +02:00
|
|
|
const DeviceInfo& info = devices_[id];
|
|
|
|
|
|
|
|
return info.drive_name.isEmpty() ? info.volume_name : info.drive_name;
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
quint64 GioLister::DeviceCapacity(const QString& id) {
|
2010-09-11 14:29:44 +02:00
|
|
|
return LockAndGetDeviceInfo(id, &DeviceInfo::filesystem_size);
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
quint64 GioLister::DeviceFreeSpace(const QString& id) {
|
2010-09-11 14:29:44 +02:00
|
|
|
return LockAndGetDeviceInfo(id, &DeviceInfo::filesystem_free);
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QString GioLister::MakeFriendlyName(const QString& id) {
|
2010-07-17 19:18:02 +02:00
|
|
|
return DeviceModel(id);
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QVariantMap GioLister::DeviceHardwareInfo(const QString& id) {
|
2010-07-17 19:18:02 +02:00
|
|
|
QVariantMap ret;
|
|
|
|
|
|
|
|
QMutexLocker l(&mutex_);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!devices_.contains(id)) return ret;
|
2010-09-11 14:29:44 +02:00
|
|
|
const DeviceInfo& info = devices_[id];
|
2010-07-17 19:18:02 +02:00
|
|
|
|
|
|
|
ret[QT_TR_NOOP("Mount point")] = info.mount_path;
|
2010-09-11 14:29:44 +02:00
|
|
|
ret[QT_TR_NOOP("Device")] = info.volume_unix_device;
|
|
|
|
ret[QT_TR_NOOP("URI")] = info.mount_uri;
|
2010-07-17 19:18:02 +02:00
|
|
|
return ret;
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
QList<QUrl> GioLister::MakeDeviceUrls(const QString& id) {
|
2010-08-01 13:55:01 +02:00
|
|
|
QString mount_point;
|
|
|
|
QString uri;
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
2010-09-11 14:29:44 +02:00
|
|
|
mount_point = devices_[id].mount_path;
|
|
|
|
uri = devices_[id].mount_uri;
|
2010-08-01 13:55:01 +02:00
|
|
|
}
|
2010-07-17 19:18:02 +02:00
|
|
|
|
2010-08-14 17:57:05 +02:00
|
|
|
// gphoto2 gives invalid hostnames with []:, characters in
|
|
|
|
uri.replace(QRegExp("//\\[usb:(\\d+),(\\d+)\\]"), "//usb-\\1-\\2");
|
|
|
|
|
2011-04-12 19:27:01 +02:00
|
|
|
QUrl url(uri);
|
|
|
|
|
2010-08-01 13:55:01 +02:00
|
|
|
QList<QUrl> ret;
|
2011-04-12 19:27:01 +02:00
|
|
|
|
|
|
|
// Special case for file:// GIO URIs - we have to check whether they point
|
|
|
|
// to an ipod.
|
|
|
|
if (url.isValid() && url.scheme() == "file") {
|
|
|
|
ret << MakeUrlFromLocalPath(url.path());
|
|
|
|
} else {
|
|
|
|
ret << url;
|
|
|
|
}
|
|
|
|
|
2010-08-14 17:57:05 +02:00
|
|
|
ret << MakeUrlFromLocalPath(mount_point);
|
2010-08-01 13:55:01 +02:00
|
|
|
return ret;
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2010-09-04 14:34:01 +02:00
|
|
|
void GioLister::VolumeAddedCallback(GVolumeMonitor*, GVolume* v, gpointer d) {
|
|
|
|
static_cast<GioLister*>(d)->VolumeAdded(v);
|
|
|
|
}
|
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
void GioLister::VolumeRemovedCallback(GVolumeMonitor*, GVolume* v, gpointer d) {
|
|
|
|
static_cast<GioLister*>(d)->VolumeRemoved(v);
|
|
|
|
}
|
|
|
|
|
2010-07-17 16:22:07 +02:00
|
|
|
void GioLister::MountAddedCallback(GVolumeMonitor*, GMount* m, gpointer d) {
|
|
|
|
static_cast<GioLister*>(d)->MountAdded(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GioLister::MountChangedCallback(GVolumeMonitor*, GMount* m, gpointer d) {
|
|
|
|
static_cast<GioLister*>(d)->MountChanged(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GioLister::MountRemovedCallback(GVolumeMonitor*, GMount* m, gpointer d) {
|
|
|
|
static_cast<GioLister*>(d)->MountRemoved(m);
|
|
|
|
}
|
|
|
|
|
2010-09-04 14:34:01 +02:00
|
|
|
void GioLister::VolumeAdded(GVolume* volume) {
|
2010-09-11 14:29:44 +02:00
|
|
|
g_object_ref(volume);
|
|
|
|
|
|
|
|
DeviceInfo info;
|
|
|
|
info.ReadVolumeInfo(volume);
|
2011-08-18 22:10:09 +02:00
|
|
|
#ifdef HAVE_AUDIOCD
|
2011-08-18 21:34:45 +02:00
|
|
|
if (info.volume_root_uri.startsWith("cdda"))
|
|
|
|
// Audio CD devices are already handled by CDDA lister
|
|
|
|
return;
|
2011-08-18 21:41:14 +02:00
|
|
|
#endif
|
2010-09-11 14:29:44 +02:00
|
|
|
info.ReadDriveInfo(g_volume_get_drive(volume));
|
|
|
|
info.ReadMountInfo(g_volume_get_mount(volume));
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!info.is_suitable()) return;
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
devices_[info.unique_id()] = info;
|
2010-09-04 14:34:01 +02:00
|
|
|
}
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
emit DeviceAdded(info.unique_id());
|
2010-09-04 14:34:01 +02:00
|
|
|
}
|
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
void GioLister::VolumeRemoved(GVolume* volume) {
|
|
|
|
QString id;
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
id = FindUniqueIdByVolume(volume);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (id.isNull()) return;
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
devices_.remove(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit DeviceRemoved(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GioLister::MountAdded(GMount* mount) {
|
|
|
|
g_object_ref(mount);
|
|
|
|
|
|
|
|
DeviceInfo info;
|
|
|
|
info.ReadVolumeInfo(g_mount_get_volume(mount));
|
2011-08-18 22:10:09 +02:00
|
|
|
#ifdef HAVE_AUDIOCD
|
2011-08-05 02:15:16 +02:00
|
|
|
if (info.volume_root_uri.startsWith("cdda"))
|
|
|
|
// Audio CD devices are already handled by CDDA lister
|
|
|
|
return;
|
2011-08-18 21:41:14 +02:00
|
|
|
#endif
|
2011-08-18 21:34:45 +02:00
|
|
|
info.ReadMountInfo(mount);
|
|
|
|
info.ReadDriveInfo(g_mount_get_drive(mount));
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!info.is_suitable()) return;
|
2010-07-17 19:18:02 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
QString old_id;
|
2010-07-17 19:18:02 +02:00
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
// The volume might already exist - either mounted or unmounted.
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const QString& id : devices_.keys()) {
|
2010-09-11 14:29:44 +02:00
|
|
|
if (devices_[id].volume == info.volume) {
|
|
|
|
old_id = id;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!old_id.isEmpty() && old_id != info.unique_id()) {
|
|
|
|
// If the ID has changed (for example, after it's been mounted), we need
|
|
|
|
// to remove the old device.
|
|
|
|
devices_.remove(old_id);
|
|
|
|
emit DeviceRemoved(old_id);
|
|
|
|
|
|
|
|
old_id = QString();
|
|
|
|
}
|
|
|
|
devices_[info.unique_id()] = info;
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
if (!old_id.isEmpty())
|
|
|
|
emit DeviceChanged(old_id);
|
2011-08-05 02:15:16 +02:00
|
|
|
else {
|
2010-09-11 14:29:44 +02:00
|
|
|
emit DeviceAdded(info.unique_id());
|
2011-08-05 02:15:16 +02:00
|
|
|
}
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
void GioLister::MountChanged(GMount* mount) {
|
2010-07-17 19:18:02 +02:00
|
|
|
QString id;
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
id = FindUniqueIdByMount(mount);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (id.isNull()) return;
|
2010-07-17 19:18:02 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
g_object_ref(mount);
|
|
|
|
|
|
|
|
DeviceInfo new_info;
|
|
|
|
new_info.ReadMountInfo(mount);
|
|
|
|
new_info.ReadVolumeInfo(g_mount_get_volume(mount));
|
|
|
|
new_info.ReadDriveInfo(g_mount_get_drive(mount));
|
2010-07-25 03:07:51 +02:00
|
|
|
|
|
|
|
// Ignore the change if the new info is useless
|
2010-09-12 21:20:06 +02:00
|
|
|
if (new_info.invalid_enclosing_mount ||
|
|
|
|
(devices_[id].filesystem_size != 0 && new_info.filesystem_size == 0) ||
|
2014-02-07 16:34:20 +01:00
|
|
|
(!devices_[id].filesystem_type.isEmpty() &&
|
|
|
|
new_info.filesystem_type.isEmpty()))
|
2010-07-25 03:07:51 +02:00
|
|
|
return;
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
devices_[id] = new_info;
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
emit DeviceChanged(id);
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GioLister::MountRemoved(GMount* mount) {
|
2010-07-17 19:18:02 +02:00
|
|
|
QString id;
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
id = FindUniqueIdByMount(mount);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (id.isNull()) return;
|
2010-07-17 19:18:02 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
devices_.remove(id);
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
emit DeviceRemoved(id);
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QString GioLister::DeviceInfo::ConvertAndFree(char* str) {
|
2010-07-17 19:18:02 +02:00
|
|
|
QString ret = QString::fromUtf8(str);
|
|
|
|
g_free(str);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
void GioLister::DeviceInfo::ReadMountInfo(GMount* mount) {
|
2010-07-17 19:18:02 +02:00
|
|
|
// Get basic information
|
2010-09-11 14:29:44 +02:00
|
|
|
this->mount.reset_without_add(mount);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!mount) return;
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
mount_name = ConvertAndFree(g_mount_get_name(mount));
|
2010-07-17 19:18:02 +02:00
|
|
|
|
|
|
|
// Get the icon name(s)
|
2010-09-11 14:29:44 +02:00
|
|
|
mount_icon_names.clear();
|
2010-07-17 19:18:02 +02:00
|
|
|
GIcon* icon = g_mount_get_icon(mount);
|
|
|
|
if (G_IS_THEMED_ICON(icon)) {
|
2014-02-07 16:34:20 +01:00
|
|
|
const char* const* icons = g_themed_icon_get_names(G_THEMED_ICON(icon));
|
|
|
|
for (const char* const* p = icons; *p; ++p) {
|
2010-09-11 14:29:44 +02:00
|
|
|
mount_icon_names << QString::fromUtf8(*p);
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
g_object_unref(icon);
|
|
|
|
|
|
|
|
GFile* root = g_mount_get_root(mount);
|
|
|
|
|
|
|
|
// Get the mount path
|
2010-09-11 14:29:44 +02:00
|
|
|
mount_path = ConvertAndFree(g_file_get_path(root));
|
|
|
|
mount_uri = ConvertAndFree(g_file_get_uri(root));
|
2010-07-17 19:18:02 +02:00
|
|
|
|
2010-09-12 21:20:06 +02:00
|
|
|
// Do a sanity check to make sure the root is actually this mount - when a
|
|
|
|
// device is unmounted GIO sends a changed signal before the removed signal,
|
|
|
|
// and we end up reading information about the / filesystem by mistake.
|
2014-02-06 16:49:49 +01:00
|
|
|
GError* error = nullptr;
|
|
|
|
GMount* actual_mount = g_file_find_enclosing_mount(root, nullptr, &error);
|
2010-09-12 21:20:06 +02:00
|
|
|
if (error || !actual_mount) {
|
|
|
|
g_error_free(error);
|
|
|
|
invalid_enclosing_mount = true;
|
|
|
|
} else if (actual_mount) {
|
|
|
|
g_object_unref(actual_mount);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Query the filesystem info for size, free space, and type
|
2014-02-06 16:49:49 +01:00
|
|
|
error = nullptr;
|
2014-02-07 16:34:20 +01:00
|
|
|
GFileInfo* info = g_file_query_filesystem_info(
|
|
|
|
root, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE
|
|
|
|
"," G_FILE_ATTRIBUTE_FILESYSTEM_FREE "," G_FILE_ATTRIBUTE_FILESYSTEM_TYPE,
|
|
|
|
nullptr, &error);
|
2010-07-17 19:18:02 +02:00
|
|
|
if (error) {
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Warning) << error->message;
|
2010-07-17 19:18:02 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2010-09-11 14:29:44 +02:00
|
|
|
filesystem_size = g_file_info_get_attribute_uint64(
|
2010-07-17 19:18:02 +02:00
|
|
|
info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE);
|
2010-09-11 14:29:44 +02:00
|
|
|
filesystem_free = g_file_info_get_attribute_uint64(
|
2010-07-17 19:18:02 +02:00
|
|
|
info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
|
2010-09-11 14:29:44 +02:00
|
|
|
filesystem_type = QString::fromUtf8(g_file_info_get_attribute_string(
|
2010-07-17 19:18:02 +02:00
|
|
|
info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE));
|
|
|
|
g_object_unref(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Query the file's info for a filesystem ID
|
|
|
|
// Only afc devices (that I know of) give reliably unique IDs
|
2010-09-11 14:29:44 +02:00
|
|
|
if (filesystem_type == "afc") {
|
2014-02-06 16:49:49 +01:00
|
|
|
error = nullptr;
|
2010-07-17 19:18:02 +02:00
|
|
|
info = g_file_query_info(root, G_FILE_ATTRIBUTE_ID_FILESYSTEM,
|
2014-02-06 16:49:49 +01:00
|
|
|
G_FILE_QUERY_INFO_NONE, nullptr, &error);
|
2010-07-17 19:18:02 +02:00
|
|
|
if (error) {
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Warning) << error->message;
|
2010-07-17 19:18:02 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2010-09-11 14:29:44 +02:00
|
|
|
mount_uuid = QString::fromUtf8(g_file_info_get_attribute_string(
|
2010-07-17 19:18:02 +02:00
|
|
|
info, G_FILE_ATTRIBUTE_ID_FILESYSTEM));
|
|
|
|
g_object_unref(info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref(root);
|
2010-09-11 14:29:44 +02:00
|
|
|
}
|
2010-07-17 19:18:02 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
void GioLister::DeviceInfo::ReadVolumeInfo(GVolume* volume) {
|
|
|
|
this->volume.reset_without_add(volume);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!volume) return;
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
volume_name = ConvertAndFree(g_volume_get_name(volume));
|
|
|
|
volume_uuid = ConvertAndFree(g_volume_get_uuid(volume));
|
2014-02-07 16:34:20 +01:00
|
|
|
volume_unix_device = ConvertAndFree(
|
|
|
|
g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
GFile* root = g_volume_get_activation_root(volume);
|
|
|
|
if (root) {
|
|
|
|
volume_root_uri = g_file_get_uri(root);
|
|
|
|
g_object_unref(root);
|
2010-07-18 00:06:19 +02:00
|
|
|
}
|
2010-09-11 14:29:44 +02:00
|
|
|
}
|
2010-07-18 00:06:19 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
void GioLister::DeviceInfo::ReadDriveInfo(GDrive* drive) {
|
|
|
|
this->drive.reset_without_add(drive);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!drive) return;
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
drive_name = ConvertAndFree(g_drive_get_name(drive));
|
|
|
|
drive_removable = g_drive_is_media_removable(drive);
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QString GioLister::FindUniqueIdByMount(GMount* mount) const {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const DeviceInfo& info : devices_) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (info.mount == mount) return info.unique_id();
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
|
|
|
return QString();
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
2010-07-25 03:07:51 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
QString GioLister::FindUniqueIdByVolume(GVolume* volume) const {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const DeviceInfo& info : devices_) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (info.volume == volume) return info.unique_id();
|
2010-09-11 14:29:44 +02:00
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GioLister::VolumeEjectFinished(GObject* object, GAsyncResult* result,
|
|
|
|
gpointer) {
|
|
|
|
OperationFinished<GVolume>(
|
|
|
|
std::bind(g_volume_eject_with_operation_finish, _1, _2, _3), object,
|
|
|
|
result);
|
2010-07-25 03:07:51 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GioLister::MountEjectFinished(GObject* object, GAsyncResult* result,
|
|
|
|
gpointer) {
|
|
|
|
OperationFinished<GMount>(
|
|
|
|
std::bind(g_mount_eject_with_operation_finish, _1, _2, _3), object,
|
|
|
|
result);
|
2010-07-25 03:07:51 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GioLister::MountUnmountFinished(GObject* object, GAsyncResult* result,
|
|
|
|
gpointer) {
|
|
|
|
OperationFinished<GMount>(
|
|
|
|
std::bind(g_mount_unmount_with_operation_finish, _1, _2, _3), object,
|
|
|
|
result);
|
2010-07-25 03:07:51 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GioLister::UnmountDevice(const QString& id) {
|
2010-09-11 14:29:44 +02:00
|
|
|
QMutexLocker l(&mutex_);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!devices_.contains(id)) return;
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
const DeviceInfo& info = devices_[id];
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!info.mount) return;
|
2010-07-25 03:07:51 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
if (info.volume) {
|
|
|
|
if (g_volume_can_eject(info.volume)) {
|
2011-10-26 11:51:11 +02:00
|
|
|
g_volume_eject_with_operation(
|
2014-02-07 16:34:20 +01:00
|
|
|
info.volume, G_MOUNT_UNMOUNT_NONE, nullptr, nullptr,
|
|
|
|
(GAsyncReadyCallback)VolumeEjectFinished, nullptr);
|
2010-09-11 14:29:44 +02:00
|
|
|
g_object_unref(info.volume);
|
2010-07-25 03:07:51 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
if (g_mount_can_eject(info.mount)) {
|
2011-10-26 11:51:11 +02:00
|
|
|
g_mount_eject_with_operation(
|
2014-02-07 16:34:20 +01:00
|
|
|
info.mount, G_MOUNT_UNMOUNT_NONE, nullptr, nullptr,
|
|
|
|
(GAsyncReadyCallback)MountEjectFinished, nullptr);
|
2010-09-11 14:29:44 +02:00
|
|
|
} else if (g_mount_can_unmount(info.mount)) {
|
2011-10-26 12:06:51 +02:00
|
|
|
g_mount_unmount_with_operation(
|
2014-02-07 16:34:20 +01:00
|
|
|
info.mount, G_MOUNT_UNMOUNT_NONE, nullptr, nullptr,
|
|
|
|
(GAsyncReadyCallback)MountUnmountFinished, nullptr);
|
2010-07-25 03:07:51 +02:00
|
|
|
}
|
|
|
|
}
|
2010-08-11 20:47:53 +02:00
|
|
|
|
|
|
|
void GioLister::UpdateDeviceFreeSpace(const QString& id) {
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!devices_.contains(id)) return;
|
2010-08-11 20:47:53 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
DeviceInfo& device_info = devices_[id];
|
2010-08-11 20:47:53 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
GFile* root = g_mount_get_root(device_info.mount);
|
2010-08-11 20:47:53 +02:00
|
|
|
|
2014-02-06 16:49:49 +01:00
|
|
|
GError* error = nullptr;
|
2010-08-11 20:47:53 +02:00
|
|
|
GFileInfo* info = g_file_query_filesystem_info(
|
2014-02-06 16:49:49 +01:00
|
|
|
root, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, nullptr, &error);
|
2010-08-11 20:47:53 +02:00
|
|
|
if (error) {
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Warning) << error->message;
|
2010-08-11 20:47:53 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2010-09-11 14:29:44 +02:00
|
|
|
device_info.filesystem_free = g_file_info_get_attribute_uint64(
|
2010-08-11 20:47:53 +02:00
|
|
|
info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
|
|
|
|
g_object_unref(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref(root);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit DeviceChanged(id);
|
|
|
|
}
|
2010-09-11 14:29:44 +02:00
|
|
|
|
|
|
|
bool GioLister::DeviceNeedsMount(const QString& id) {
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
return devices_.contains(id) && !devices_[id].mount;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GioLister::MountDevice(const QString& id) {
|
2014-02-07 16:34:20 +01:00
|
|
|
const int request_id = next_mount_request_id_++;
|
2010-09-11 14:29:44 +02:00
|
|
|
metaObject()->invokeMethod(this, "DoMountDevice", Qt::QueuedConnection,
|
|
|
|
Q_ARG(QString, id), Q_ARG(int, request_id));
|
|
|
|
return request_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GioLister::DoMountDevice(const QString& id, int request_id) {
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
if (!devices_.contains(id)) {
|
|
|
|
emit DeviceMounted(id, request_id, false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const DeviceInfo& info = devices_[id];
|
|
|
|
if (info.mount) {
|
|
|
|
// Already mounted
|
|
|
|
emit DeviceMounted(id, request_id, true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-06 16:49:49 +01:00
|
|
|
g_volume_mount(info.volume, G_MOUNT_MOUNT_NONE, nullptr, nullptr,
|
|
|
|
VolumeMountFinished, nullptr);
|
2010-09-11 14:29:44 +02:00
|
|
|
emit DeviceMounted(id, request_id, true);
|
|
|
|
}
|