[gnome-disk-utility] Resize and repair helper functions
- From: Kai Lüke <kailueke src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility] Resize and repair helper functions
- Date: Mon, 7 Aug 2017 21:38:33 +0000 (UTC)
commit e36e64dfa560c1e84d95ba50b1f71ca8541e9b16
Author: Kai Lüke <kailueke riseup net>
Date: Sat Aug 5 12:21:25 2017 +0200
Resize and repair helper functions
The filesystem support for resize, check
and repair actions is cached after queried
and the minimal and maximal size of (external)
partitions calculated.
src/libgdu/gduutils.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++
src/libgdu/gduutils.h | 36 ++++++++
2 files changed, 271 insertions(+), 0 deletions(-)
---
diff --git a/src/libgdu/gduutils.c b/src/libgdu/gduutils.c
index bcc5d41..d9ab9e1 100644
--- a/src/libgdu/gduutils.c
+++ b/src/libgdu/gduutils.c
@@ -871,6 +871,170 @@ gdu_utils_is_ntfs_available (void)
/* ---------------------------------------------------------------------------------------------------- */
+#ifdef HAVE_UDISKS2_7_2
+
+typedef struct
+{
+ gboolean available;
+ gchar *missing_util;
+ ResizeFlags mode;
+} UtilCacheEntry;
+
+static void
+util_cache_entry_free (UtilCacheEntry *data)
+{
+ g_free (data->missing_util);
+ g_free (data);
+}
+
+G_LOCK_DEFINE (can_resize_lock);
+
+/* Uses an internal cache, set flush to rebuild it first */
+gboolean
+gdu_utils_can_resize (UDisksClient *client,
+ const gchar *fstype,
+ gboolean flush,
+ ResizeFlags *mode_out,
+ gchar **missing_util_out)
+{
+ static GHashTable *cache = NULL;
+ const gchar *const *supported_fs;
+ UtilCacheEntry *result;
+
+ G_LOCK (can_resize_lock);
+ if (flush)
+ g_clear_pointer (&cache, g_hash_table_destroy);
+
+ if (cache == NULL)
+ {
+ cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)
util_cache_entry_free);
+ supported_fs = udisks_manager_get_supported_filesystems (udisks_client_get_manager (client));
+ for (gsize i = 0; supported_fs[i] != NULL; i++)
+ {
+ GVariant *out_available;
+
+ if (udisks_manager_call_can_resize_sync (udisks_client_get_manager (client),
+ supported_fs[i], &out_available, NULL, NULL))
+ {
+ UtilCacheEntry *entry;
+ guint64 m = 0;
+
+ entry = g_new0 (UtilCacheEntry, 1);
+ g_variant_get (out_available, "(bts)", &entry->available, &m, &entry->missing_util);
+ g_variant_unref (out_available);
+ entry->mode = (ResizeFlags) m;
+ g_hash_table_insert (cache, g_strdup (supported_fs[i]), entry);
+ }
+ }
+ }
+ G_UNLOCK (can_resize_lock);
+
+ result = g_hash_table_lookup (cache, fstype);
+ if (mode_out != NULL)
+ *mode_out = result ? result->mode : 0;
+
+ if (missing_util_out != NULL)
+ *missing_util_out = result ? g_strdup (result->missing_util) : NULL;
+
+ return result ? result->available : FALSE;
+}
+
+G_LOCK_DEFINE (can_repair_lock);
+
+gboolean
+gdu_utils_can_repair (UDisksClient *client,
+ const gchar *fstype,
+ gboolean flush,
+ gchar **missing_util_out)
+{
+ static GHashTable *cache = NULL;
+ const gchar *const *supported_fs;
+ UtilCacheEntry *result;
+
+ G_LOCK (can_repair_lock);
+ if (flush)
+ g_clear_pointer (&cache, g_hash_table_destroy);
+
+ if (cache == NULL)
+ {
+ cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)
util_cache_entry_free);
+ supported_fs = udisks_manager_get_supported_filesystems (udisks_client_get_manager (client));
+ for (gsize i = 0; supported_fs[i] != NULL; i++)
+ {
+ GVariant *out_available;
+
+ if (udisks_manager_call_can_repair_sync (udisks_client_get_manager (client),
+ supported_fs[i], &out_available, NULL, NULL))
+ {
+ UtilCacheEntry *entry;
+
+ entry = g_new0 (UtilCacheEntry, 1);
+ g_variant_get (out_available, "(bs)", &entry->available, &entry->missing_util);
+ g_variant_unref (out_available);
+ g_hash_table_insert (cache, g_strdup (supported_fs[i]), entry);
+ }
+ }
+ }
+ G_UNLOCK (can_repair_lock);
+
+ result = g_hash_table_lookup (cache, fstype);
+ if (missing_util_out != NULL)
+ *missing_util_out = result ? g_strdup (result->missing_util) : NULL;
+
+ return result ? result->available : FALSE;
+}
+
+G_LOCK_DEFINE (can_check_lock);
+
+gboolean
+gdu_utils_can_check (UDisksClient *client,
+ const gchar *fstype,
+ gboolean flush,
+ gchar **missing_util_out)
+{
+ static GHashTable *cache = NULL;
+ const gchar *const *supported_fs;
+ UtilCacheEntry *result;
+
+ G_LOCK (can_check_lock);
+ if (flush && cache != NULL)
+ g_clear_pointer (&cache, g_hash_table_destroy);
+
+ if (cache == NULL)
+ {
+ cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)
util_cache_entry_free);
+ supported_fs = udisks_manager_get_supported_filesystems (udisks_client_get_manager (client));
+ for (gsize i = 0; supported_fs[i] != NULL; i++)
+ {
+ GVariant *out_available;
+
+ if (udisks_manager_call_can_check_sync (udisks_client_get_manager (client),
+ supported_fs[i], &out_available, NULL, NULL))
+ {
+ UtilCacheEntry *entry;
+ guint64 m = 0;
+
+ entry = g_new0 (UtilCacheEntry, 1);
+ g_variant_get (out_available, "(bs)", &entry->available, &entry->missing_util);
+ g_variant_unref (out_available);
+ entry->mode = (ResizeFlags) m;
+ g_hash_table_insert (cache, g_strdup (supported_fs[i]), entry);
+ }
+ }
+ }
+ G_UNLOCK (can_check_lock);
+
+ result = g_hash_table_lookup (cache, fstype);
+ if (missing_util_out != NULL)
+ *missing_util_out = result ? g_strdup (result->missing_util) : NULL;
+
+ return result ? result->available : FALSE;
+}
+
+#endif
+
+/* ---------------------------------------------------------------------------------------------------- */
+
guint
gdu_utils_get_max_label_length (const gchar *fstype)
{
@@ -1396,6 +1560,77 @@ gdu_utils_ensure_unused_finish (UDisksClient *client,
/* ---------------------------------------------------------------------------------------------------- */
+guint64
+gdu_utils_calc_space_to_grow (UDisksClient *client,
+ UDisksPartitionTable *table,
+ UDisksPartition *partition)
+{
+ GList *partitions, *l;
+ guint64 next_pos, current_end;
+ UDisksObject *table_object;
+
+ table_object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (table)));
+ next_pos = udisks_block_get_size (udisks_object_peek_block (table_object));
+ current_end = udisks_partition_get_offset (partition) + udisks_partition_get_size (partition);
+ partitions = udisks_client_get_partitions (client, table);
+ for (l = partitions; l != NULL; l = l->next)
+ {
+ UDisksPartition *tmp_partition = UDISKS_PARTITION (l->data);
+ guint64 start;
+ guint64 end;
+
+ if (udisks_partition_get_number (partition) == udisks_partition_get_number (tmp_partition))
+ continue;
+
+ start = udisks_partition_get_offset (tmp_partition);
+ end = start + udisks_partition_get_size (tmp_partition);
+ if (end > current_end && (end < next_pos))
+ next_pos = end;
+ if (start >= current_end && (start < next_pos))
+ next_pos = start;
+ }
+
+ g_list_foreach (partitions, (GFunc) g_object_unref, NULL);
+ g_list_free (partitions);
+
+ return next_pos - udisks_partition_get_offset (partition);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+guint64
+gdu_utils_calc_space_to_shrink_extended (UDisksClient *client,
+ UDisksPartitionTable *table,
+ UDisksPartition *partition)
+{
+ GList *partitions, *l;
+ guint64 minimum, maximum;
+
+ g_assert (udisks_partition_get_is_container (partition));
+ minimum = udisks_partition_get_offset (partition) + 1;
+ maximum = minimum + udisks_partition_get_size (partition);
+ partitions = udisks_client_get_partitions (client, table);
+ for (l = partitions; l != NULL; l = l->next)
+ {
+ UDisksPartition *tmp_partition = UDISKS_PARTITION (l->data);
+ guint64 end;
+
+ if (udisks_partition_get_number (partition) == udisks_partition_get_number (tmp_partition))
+ continue;
+
+ end = udisks_partition_get_offset (tmp_partition) + udisks_partition_get_size (tmp_partition);
+ if (end > minimum && end <= maximum)
+ minimum = end;
+ }
+
+ g_list_foreach (partitions, (GFunc) g_object_unref, NULL);
+ g_list_free (partitions);
+
+ return minimum - udisks_partition_get_offset (partition);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
gint64
gdu_utils_get_unused_for_block (UDisksClient *client,
UDisksBlock *block)
diff --git a/src/libgdu/gduutils.h b/src/libgdu/gduutils.h
index c9effa1..c54a39d 100644
--- a/src/libgdu/gduutils.h
+++ b/src/libgdu/gduutils.h
@@ -74,6 +74,34 @@ gboolean gdu_utils_show_confirmation (GtkWindow *parent_window,
gboolean gdu_utils_is_ntfs_available (void);
+#ifdef HAVE_UDISKS2_7_2
+
+/* Defined by libblockdev/UDisks */
+typedef enum {
+ OFFLINE_SHRINK = 1 << 1,
+ OFFLINE_GROW = 1 << 2,
+ ONLINE_SHRINK = 1 << 3,
+ ONLINE_GROW = 1 << 4
+} ResizeFlags;
+
+gboolean gdu_utils_can_resize (UDisksClient *client,
+ const gchar *fstype,
+ gboolean flush,
+ ResizeFlags *mode_out,
+ gchar **missing_util_out);
+
+gboolean gdu_utils_can_repair (UDisksClient *client,
+ const gchar *fstype,
+ gboolean flush,
+ gchar **missing_util_out);
+
+gboolean gdu_utils_can_check (UDisksClient *client,
+ const gchar *fstype,
+ gboolean flush,
+ gchar **missing_util_out);
+
+#endif
+
guint gdu_utils_get_max_label_length (const gchar *fstype);
gboolean _gtk_entry_buffer_truncate_bytes (GtkEntryBuffer *gtk_entry_buffer,
@@ -107,6 +135,14 @@ gboolean gdu_utils_ensure_unused_list_finish (UDisksClient *client,
GAsyncResult *res,
GError **error);
+guint64 gdu_utils_calc_space_to_grow (UDisksClient *client,
+ UDisksPartitionTable *table,
+ UDisksPartition *partition);
+
+guint64 gdu_utils_calc_space_to_shrink_extended (UDisksClient *client,
+ UDisksPartitionTable *table,
+ UDisksPartition *partition);
+
gint64 gdu_utils_get_unused_for_block (UDisksClient *client,
UDisksBlock *block);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]