enlightenment/src/bin/e_fm_device.c

798 lines
20 KiB
C

#include "e_fm_device.h"
#include "e_fm_shared_codec.h"
#include "e_fm_shared_device.h"
static void _e_fm2_volume_write(E_Volume *v) EINA_ARG_NONNULL(1);
static void _e_fm2_volume_erase(E_Volume *v) EINA_ARG_NONNULL(1);
static void _e_fm2_device_mount_ok(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
static void _e_fm2_device_mount_fail(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
static void _e_fm2_device_unmount_ok(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
static void _e_fm2_device_unmount_fail(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
static Eina_List *_e_stores = NULL;
static Eina_List *_e_vols = NULL;
static Eina_Bool _check_run_show = EINA_FALSE;
static Eina_Bool _check_run_hide = EINA_FALSE;
static Ecore_Thread *_check_vols = NULL;
static inline E_Fm2_Device_Mount_Op *
_e_fm2_device_mount_op_new(char *args, size_t size, size_t length)
{
E_Fm2_Device_Mount_Op *mop;
mop = E_NEW(E_Fm2_Device_Mount_Op, 1);
mop->args = args;
mop->size = size;
mop->length = length;
return mop;
}
static inline void
_e_fm2_device_mount_op_free(E_Fm2_Device_Mount_Op *mop)
{
if (!mop) return;
free(mop->args);
free(mop);
}
static void
_e_fm2_device_volume_setup(E_Volume *v)
{
char label[1024] = {0};
char *size = NULL;
const char *icon = NULL;
/* unsigned long long sz; */
/* Compute the size in a readable form */
if (v->size)
size = e_util_size_string_get(v->size);
/* Choose the label */
if ((v->label) && (v->label[0]))
{}else if ((v->partition_label) && (v->partition_label[0]))
snprintf(label, sizeof(label) - 1, "%s", v->partition_label);
else if (((v->storage->vendor) && (v->storage->vendor[0])) &&
((v->storage->model) && (v->storage->model[0])))
{
if (size && (size[0] != '\0'))
snprintf(label, sizeof(label) - 1, _("%s %s—%s"), v->storage->vendor, v->storage->model, size);
else
snprintf(label, sizeof(label) - 1, "%s %s", v->storage->vendor, v->storage->model);
}
else if ((v->storage->model) && (v->storage->model[0]))
{
if (size && (size[0] != '\0'))
snprintf(label, sizeof(label) - 1, _("%s—%s"), v->storage->model, size);
else
snprintf(label, sizeof(label) - 1, "%s", v->storage->model);
}
else if ((v->storage->vendor) && (v->storage->vendor[0]))
{
if (size && (size[0] != '\0'))
snprintf(label, sizeof(label) - 1, _("%s—%s"), v->storage->vendor, size);
else
snprintf(label, sizeof(label) - 1, "%s", v->storage->vendor);
}
else if (v->storage->drive_type && (!strcmp(v->storage->drive_type, "sd_mmc")))
snprintf(label, sizeof(label) - 1, _("Flash Card—%s"), size);
else
snprintf(label, sizeof(label), _("Unknown Volume"));
if (label[0]) eina_stringshare_replace(&v->label, label);
/* Choose the icon */
/* http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html */
if (v->storage->icon.volume)
icon = v->storage->icon.volume;
else
{
if ((!v->storage->drive_type) || (!strcmp(v->storage->drive_type, "disk")) || (!strcmp(v->storage->drive_type, "partition")))
{
if (v->storage->removable == 0)
icon = "drive-harddisk";
else
icon = "drive-removable-media";
}
else if ((!strcmp(v->storage->drive_type, "cdrom")) || (!strncmp(v->storage->drive_type, "optical", 7)))
icon = "drive-optical";
else if (!strncmp(v->storage->drive_type, "floppy", 6))
icon = "media-floppy";
else if (!strcmp(v->storage->drive_type, "tape"))
icon = "media-tape";
else if (!strcmp(v->storage->drive_type, "thumb"))
// XXX: maybe a spcial type?
icon = "drive-removable-media";
else if (!strcmp(v->storage->drive_type, "compact_flash")
|| !strcmp(v->storage->drive_type, "memory_stick")
|| !strcmp(v->storage->drive_type, "smart_media")
|| !strcmp(v->storage->drive_type, "sd_mmc")
|| !strncmp(v->storage->drive_type, "flash", 5))
icon = "media-flash";
else // XXX: fallback if we don't know
icon = "media-floppy";
}
if (icon) eina_stringshare_replace(&v->icon, icon);
if ((!v->mount_point) ||
// filter out these mountouts - hack hack
(strcmp(v->mount_point, "/") &&
strcmp(v->mount_point, "/home") &&
strcmp(v->mount_point, "/tmp")))
_e_fm2_volume_write(v);
E_FREE(size);
}
E_API void
e_fm2_device_storage_add(E_Storage *s)
{
Eina_List *l;
E_Volume *v;
if (e_fm2_device_storage_find(s->udi)) return;
s->validated = EINA_TRUE;
_e_stores = eina_list_append(_e_stores, s);
/*
printf("STO+\n"
" udi: %s\n"
" bus: %s\n"
" drive_type: %s\n"
" model: %s\n"
" vendor: %s\n"
" serial: %s\n"
" removable: %i\n"
" media_available: %i\n"
" media_size: %lli\n"
" requires_eject: %i\n"
" hotpluggable: %i\n"
" media_check_enabled: %i\n"
" icon.drive: %s\n"
" icon.volume: %s\n\n"
,
s->udi,
s->bus,
s->drive_type,
s->model,
s->vendor,
s->serial,
s->removable,
s->media_available,
s->media_size,
s->requires_eject,
s->hotpluggable,
s->media_check_enabled,
s->icon.drive,
s->icon.volume);
*/
if ((s->removable == 0) &&
(s->media_available == 0) &&
(s->media_size == 0) &&
(s->requires_eject == 0) &&
(s->hotpluggable == 0) &&
(s->media_check_enabled == 0))
{
// printf(" Ignore this storage\n");
}
else
{
s->trackable = EINA_TRUE;
}
EINA_LIST_FOREACH(_e_vols, l, v) /* catch volumes which were added before their storage */
{
if ((!v->storage) && (s->udi == v->parent))
{
v->storage = s;
_e_fm2_device_volume_setup(v);
}
}
}
E_API void
e_fm2_device_storage_del(E_Storage *s)
{
// printf("STO- %s\n", s->udi);
_e_stores = eina_list_remove(_e_stores, s);
_e_fm_shared_device_storage_free(s);
}
E_API E_Storage *
e_fm2_device_storage_find(const char *udi)
{
Eina_List *l;
E_Storage *s;
if (!udi) return NULL;
EINA_LIST_FOREACH(_e_stores, l, s)
{
if (!strcmp(udi, s->udi)) return s;
}
return NULL;
}
E_API void
e_fm2_device_volume_add(E_Volume *v)
{
E_Storage *s;
if (e_fm2_device_volume_find(v->udi)) return;
v->validated = EINA_TRUE;
_e_vols = eina_list_append(_e_vols, v);
/*
printf("VOL+\n"
" udi: %s\n"
" uuid: %s\n"
" fstype: %s\n"
" size: %llu\n"
" label: %s\n"
" partition: %d\n"
" partition_number: %d\n"
" partition_label: %s\n"
" mounted: %d\n"
" mount_point: %s\n"
" parent: %s\n"
,
v->udi,
v->uuid,
v->fstype,
v->size,
v->label,
v->partition,
v->partition_number,
v->partition ? v->partition_label : "(not a partition)",
v->mounted,
v->mount_point,
v->parent);
*/
/* Check mount point */
if ((v->efm_mode == EFM_MODE_USING_HAL_MOUNT) &&
((!v->mount_point) || (!v->mount_point[0])))
{
eina_stringshare_del(v->mount_point);
v->mount_point = NULL;
v->mount_point = e_fm2_device_volume_mountpoint_get(v);
if ((!v->mount_point) || (!v->mount_point[0]))
{
char buf[PATH_MAX];
const char *id;
if (v->mount_point) eina_stringshare_del(v->mount_point);
v->mount_point = NULL;
id = "disk";
if ((v->uuid) && (v->uuid[0])) id = v->uuid;
if (ecore_file_is_dir("/media"))
snprintf(buf, sizeof(buf), "/media/%s", id);
else if (ecore_file_is_dir("/mnt"))
snprintf(buf, sizeof(buf), "/mnt/%s", id);
else if (ecore_file_is_dir("/tmp"))
snprintf(buf, sizeof(buf), "/tmp/%s", id);
else
buf[0] = 0;
v->mount_point = eina_stringshare_add(buf);
}
}
/* Search parent storage */
if ((s = e_fm2_device_storage_find(v->parent)))
{
v->storage = s;
s->volumes = eina_list_append(s->volumes, v);
}
if (v->storage) _e_fm2_device_volume_setup(v);
}
E_API void
e_fm2_device_volume_del(E_Volume *v)
{
E_Fm2_Mount *m;
// printf("VOL- %s\n", v->udi);
_e_vols = eina_list_remove(_e_vols, v);
_e_fm2_volume_erase(v);
if (v->storage)
{
v->storage->volumes = eina_list_remove(v->storage->volumes, v);
v->storage = NULL;
}
EINA_LIST_FREE(v->mounts, m)
{
_e_fm2_device_unmount_ok(m);
e_fm2_device_mount_free(m);
}
while (v->mount_ops)
{
E_Fm2_Device_Mount_Op *mop;
mop = (E_Fm2_Device_Mount_Op *)v->mount_ops;
v->mount_ops = eina_inlist_remove(v->mount_ops, v->mount_ops);
_e_fm2_device_mount_op_free(mop);
}
_e_fm_shared_device_volume_free(v);
}
static void
_e_fm2_volume_write(E_Volume *v)
{
char buf[PATH_MAX], buf2[PATH_MAX];
FILE *f;
const char *id;
if (!v->storage) return;
id = ecore_file_file_get(v->storage->udi);
e_user_dir_snprintf(buf, sizeof(buf), "fileman/favorites/|%s_%d.desktop",
id, v->partition_number);
f = fopen(buf, "w");
if (f)
{
fprintf(f,
"[Desktop Entry]\n"
"Encoding=UTF-8\n"
"Type=Link\n"
"X-Enlightenment-Type=Removable\n"
"X-Enlightenment-Removable-State=Full\n"
"Name=%s\n"
"Icon=%s\n"
"Comment=%s\n"
"URL=file:/%s\n"
,
v->label,
v->icon,
_("Removable Device"),
v->udi);
fclose(f);
if (e_config->device_desktop)
{
snprintf(buf2, sizeof(buf2), "%s/|%s_%d.desktop",
efreet_desktop_dir_get(), id, v->partition_number);
ecore_file_symlink(buf, buf2);
}
/* FIXME: manipulate icon directly */
_e_fm2_file_force_update(buf);
_e_fm2_file_force_update(buf2);
}
}
static void
_e_fm2_volume_erase(E_Volume *v)
{
char buf[PATH_MAX] = {0};
const char *id;
if (!v->storage) return;
id = ecore_file_file_get(v->storage->udi);
if (e_config->device_desktop)
{
snprintf(buf, sizeof(buf), "%s/|%s_%d.desktop",
efreet_desktop_dir_get(), id, v->partition_number);
ecore_file_unlink(buf);
_e_fm2_file_force_update(buf);
}
e_user_dir_snprintf(buf, sizeof(buf),
"fileman/favorites/|%s_%d.desktop",
id, v->partition_number);
ecore_file_unlink(buf);
_e_fm2_file_force_update(buf);
}
E_API E_Volume *
e_fm2_device_volume_find(const char *udi)
{
Eina_List *l;
E_Volume *v;
if (!udi) return NULL;
EINA_LIST_FOREACH(_e_vols, l, v)
{
if (!v->udi) continue;
if (!strcmp(udi, v->udi)) return v;
}
return NULL;
}
E_API E_Volume *
e_fm2_device_volume_find_fast(const char *udi)
{
Eina_List *l;
E_Volume *v;
if (!udi) return NULL;
EINA_LIST_FOREACH(_e_vols, l, v)
if (udi == v->udi) return v;
return NULL;
}
E_API const char *
e_fm2_device_volume_mountpoint_get(E_Volume *v)
{
char buf[PATH_MAX] = {0};
if (!v) return NULL;
if (v->mount_point)
{
// printf("GET MOUNTPOINT = %s\n", v->mount_point);
return eina_stringshare_add(v->mount_point);
}
else if (v->efm_mode != EFM_MODE_USING_HAL_MOUNT)
return NULL;
if (v->label && v->label[0] != '\0')
snprintf(buf, sizeof(buf) - 1, "/media/%s", v->label);
else if (v->uuid && v->uuid[0] != '\0')
snprintf(buf, sizeof(buf) - 1, "/media/%s", v->uuid);
else if ((v->storage) && (v->storage->serial) && v->storage->serial[0] != '\0')
snprintf(buf, sizeof(buf) - 1, "/media/%s", v->storage->serial);
else
{
static int mount_count = 1;
snprintf(buf, sizeof(buf) - 1, "/media/unknown-%i", mount_count++);
}
// printf("GET MOUNTPOINT = %s\n", buf);
return eina_stringshare_add(buf);
}
E_API E_Fm2_Device_Mount_Op *
e_fm2_device_mount_op_add(E_Fm2_Mount *m, char *args, size_t size, size_t length)
{
E_Fm2_Device_Mount_Op *mop;
mop = _e_fm2_device_mount_op_new(args, size, length);
m->volume->mount_ops = eina_inlist_append(m->volume->mount_ops, EINA_INLIST_GET(mop));
return mop;
}
E_API void
e_fm2_device_mount_add(E_Volume *v,
const char *mountpoint)
{
v->mounted = EINA_TRUE;
if (mountpoint && (mountpoint[0]))
eina_stringshare_replace(&v->mount_point, mountpoint);
E_LIST_FOREACH(v->mounts, _e_fm2_device_mount_ok);
// printf("MOUNT %s %s\n", v->udi, v->mount_point);
}
E_API void
e_fm2_device_mount_del(E_Volume *v)
{
E_Fm2_Mount *m;
v->mounted = EINA_FALSE;
if (v->mount_point)
{
eina_stringshare_del(v->mount_point);
v->mount_point = NULL;
}
EINA_LIST_FREE(v->mounts, m)
{
_e_fm2_device_unmount_ok(m);
e_fm2_device_mount_free(m);
}
}
E_API void
e_fm2_device_mount_free(E_Fm2_Mount *m)
{
if (!m) return;
eina_stringshare_del(m->udi);
eina_stringshare_del(m->mount_point);
free(m);
}
E_API E_Fm2_Mount *
e_fm2_device_mount_find(const char *path)
{
Eina_List *l;
E_Volume *v;
if (!path) return NULL;
EINA_LIST_FOREACH(_e_vols, l, v)
{
if (v->mounted
&& v->mount_point
&& !strncmp(path, v->mount_point, strlen(v->mount_point))
&& v->mounts)
return eina_list_data_get(v->mounts);
}
return NULL;
}
E_API E_Fm2_Mount *
e_fm2_device_mount(E_Volume *v,
Ecore_Cb mount_ok,
Ecore_Cb mount_fail,
Ecore_Cb unmount_ok,
Ecore_Cb unmount_fail,
void *data)
{
E_Fm2_Mount *m;
if (!v) return NULL;
m = calloc(1, sizeof(E_Fm2_Mount));
if (!m) return NULL;
m->udi = eina_stringshare_add(v->udi);
m->mount_ok = mount_ok;
m->mount_fail = mount_fail;
m->unmount_ok = unmount_ok;
m->unmount_fail = unmount_fail;
m->data = data;
m->volume = v;
m->mounted = v->mounted;
v->mounts = eina_list_prepend(v->mounts, m);
if (!v->mounted)
{
//printf("BEGIN MOUNT %p '%s'\n", m, v->mount_point);
v->auto_unmount = EINA_TRUE;
_e_fm2_client_mount(v->udi, v->mount_point);
}
else
{
v->auto_unmount = EINA_FALSE;
m->mount_point = eina_stringshare_add(v->mount_point);
}
return m;
}
E_API void
e_fm2_device_mount_fail(E_Volume *v)
{
E_Fm2_Mount *m;
v->mounted = EINA_FALSE;
if (v->mount_point)
{
eina_stringshare_del(v->mount_point);
v->mount_point = NULL;
}
EINA_LIST_FREE(v->mounts, m)
{
_e_fm2_device_mount_fail(m);
e_fm2_device_mount_free(m);
}
}
E_API void
e_fm2_device_unmount(E_Fm2_Mount *m)
{
E_Volume *v;
if (!(v = m->volume)) return;
if (v->mount_ops)
{
m->deleted = EINA_TRUE;
return;
}
v->mounts = eina_list_remove(v->mounts, m);
e_fm2_device_mount_free(m);
if (v->auto_unmount && v->mounted && !eina_list_count(v->mounts))
{
//printf("BEGIN UNMOUNT %p '%s'\n", m, v->udi);
_e_fm2_client_unmount(v->udi);
}
}
E_API void
e_fm2_device_unmount_fail(E_Volume *v)
{
Eina_List *l;
E_Fm2_Mount *m;
v->mounted = EINA_TRUE;
EINA_LIST_FOREACH(v->mounts, l, m)
_e_fm2_device_unmount_fail(m);
}
static void
_e_fm2_device_mount_ok(E_Fm2_Mount *m)
{
if (m->mounted) return;
m->mounted = EINA_TRUE;
if (m->volume)
m->mount_point = eina_stringshare_add(m->volume->mount_point);
if (m->mount_ok)
m->mount_ok(m->data);
if (m->deleted) ecore_job_add((Ecore_Cb)e_fm2_device_unmount, m);
//printf("MOUNT OK '%s'\n", m->mount_point);
}
static void
_e_fm2_device_mount_fail(E_Fm2_Mount *m)
{
//printf("MOUNT FAIL '%s'\n", m->mount_point);
m->mounted = EINA_FALSE;
if (m->mount_point)
{
eina_stringshare_del(m->mount_point);
m->mount_point = NULL;
}
if (m->mount_fail)
m->mount_fail(m->data);
}
static void
_e_fm2_device_unmount_ok(E_Fm2_Mount *m)
{
if (!m->mounted) return;
m->mounted = EINA_FALSE;
if (m->mount_point)
{
eina_stringshare_del(m->mount_point);
m->mount_point = NULL;
}
if (m->unmount_ok)
m->unmount_ok(m->data);
}
static void
_e_fm2_device_unmount_fail(E_Fm2_Mount *m)
{
if (m->mounted) return;
m->mounted = EINA_TRUE;
if (m->unmount_fail)
m->unmount_fail(m->data);
}
static void
_e_fm2_device_check_desktop_icons_cb_end(void *data EINA_UNUSED, Ecore_Thread *eth EINA_UNUSED)
{
_check_vols = NULL;
if (_check_run_show)
e_fm2_device_show_desktop_icons();
else if (_check_run_hide)
e_fm2_device_hide_desktop_icons();
_check_run_hide = _check_run_show = EINA_FALSE;
}
static void
_e_fm2_device_check_desktop_icons_list_cb(const char *name, const char *path, void *data)
{
char buf[PATH_MAX], buf2[PATH_MAX];
Eina_List *l;
char *file;
if (path[0] != '|') return; // not e17 link
if (!eina_str_has_extension(name, ".desktop")) return;
snprintf(buf, sizeof(buf), "%s/%s", path, name);
if (ecore_file_size(buf) > 200) return; // unlikely that we're going to write a desktop file this long
e_user_dir_snprintf(buf2, sizeof(buf2), "fileman/favorites/%s", name);
if (!ecore_file_exists(buf2)) return;
EINA_LIST_FOREACH(data, l, file)
if (!strcmp(file, buf)) return; // valid link
ecore_file_unlink(buf);
ecore_file_unlink(buf2);
}
static void
_e_fm2_device_check_desktop_icons_cb(void *data, Ecore_Thread *eth EINA_UNUSED)
{
Eina_List *list = data;
eina_file_dir_list(efreet_desktop_dir_get(), EINA_FALSE, _e_fm2_device_check_desktop_icons_list_cb, data);
E_FREE_LIST(list, free);
}
E_API void
e_fm2_device_show_desktop_icons(void)
{
Eina_List *l;
E_Volume *v;
char buf[PATH_MAX] = {0};
char buf2[PATH_MAX] = {0};
const char *id;
if (_check_vols)
{
_check_run_hide = EINA_FALSE;
_check_run_show = EINA_TRUE;
return;
}
EINA_LIST_FOREACH(_e_vols, l, v)
{
if (!v) continue;
if (!v->storage) continue;
id = ecore_file_file_get(v->storage->udi);
e_user_dir_snprintf(buf, sizeof(buf),
"fileman/favorites/|%s_%d.desktop",
id, v->partition_number);
snprintf(buf2, sizeof(buf2), "%s/|%s_%d.desktop",
efreet_desktop_dir_get(), id, v->partition_number);
if (ecore_file_exists(buf) && !ecore_file_exists(buf2))
{
ecore_file_symlink(buf, buf2);
_e_fm2_file_force_update(buf2);
}
}
}
E_API void
e_fm2_device_hide_desktop_icons(void)
{
Eina_List *l;
E_Volume *v;
char buf[PATH_MAX] = {0};
const char *id;
if (_check_vols)
{
_check_run_show = EINA_FALSE;
_check_run_hide = EINA_TRUE;
return;
}
EINA_LIST_FOREACH(_e_vols, l, v)
{
if (!v) continue;
if (!v->storage) continue;
id = ecore_file_file_get(v->storage->udi);
snprintf(buf, sizeof(buf), "%s/|%s_%d.desktop",
efreet_desktop_dir_get(), id, v->partition_number);
if (ecore_file_exists(buf))
{
ecore_file_unlink(buf);
_e_fm2_file_force_update(buf);
}
}
}
E_API void
e_fm2_device_check_desktop_icons(void)
{
Eina_List *l, *thd = NULL;
E_Volume *v;
char buf[PATH_MAX] = {0};
const char *id;
if (_check_vols) return;
EINA_LIST_FOREACH(_e_vols, l, v)
{
if (!v) continue;
if (!v->storage) continue;
id = ecore_file_file_get(v->storage->udi);
snprintf(buf, sizeof(buf), "%s/|%s_%d.desktop",
efreet_desktop_dir_get(), id, v->partition_number);
thd = eina_list_append(thd, strdup(buf));
}
_check_vols = ecore_thread_run(_e_fm2_device_check_desktop_icons_cb, _e_fm2_device_check_desktop_icons_cb_end, _e_fm2_device_check_desktop_icons_cb_end, thd);
}
E_API Eina_List *
e_fm2_device_volume_list_get(void)
{
return _e_vols;
}