[gnome-disk-utility] Use abstract interface to create volumes
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility] Use abstract interface to create volumes
- Date: Fri, 5 Feb 2010 00:17:03 +0000 (UTC)
commit f247a3903b80a9548a51db345a09d5fe909f0e64
Author: David Zeuthen <davidz redhat com>
Date: Thu Feb 4 16:19:11 2010 -0500
Use abstract interface to create volumes
This makes it possible to e.g. select a VG when creating a RAID array.
src/gdu-gtk/gdu-disk-selection-widget.c | 486 ++++++++++++++------
src/gdu-gtk/gdu-pool-tree-model.c | 2 +-
src/gdu/gdu-drive.c | 407 +++++++++++++++--
src/gdu/gdu-drive.h | 49 ++-
src/gdu/gdu-linux-lvm2-volume-group.c | 172 +++++++
src/gdu/gdu-linux-md-drive.c | 8 +-
src/gdu/gdu-pool.c | 1 +
.../gdu-section-linux-lvm2-volume-group.c | 10 +-
src/palimpsest/gdu-section-linux-md-drive.c | 10 +-
src/palimpsest/gdu-shell.c | 130 +-----
10 files changed, 948 insertions(+), 327 deletions(-)
---
diff --git a/src/gdu-gtk/gdu-disk-selection-widget.c b/src/gdu-gtk/gdu-disk-selection-widget.c
index 0cdeb20..287e300 100644
--- a/src/gdu-gtk/gdu-disk-selection-widget.c
+++ b/src/gdu-gtk/gdu-disk-selection-widget.c
@@ -33,6 +33,8 @@
#define DETAILS_WIDTH 180
#define DETAILS_MARGIN 12
+#define SIZE_EPSILON 1000
+
struct GduDiskSelectionWidgetPrivate
{
GduPool *pool;
@@ -397,6 +399,63 @@ gdu_disk_selection_widget_get_ignored_drives (GduDiskSelectionWidget *widget)
/* ---------------------------------------------------------------------------------------------------- */
+typedef enum {
+ REASON_INSUFFICIENT_SPACE,
+ REASON_MULTIPATH_COMPONENT,
+} Reason;
+
+static gboolean
+is_drive_selectable (GduDiskSelectionWidget *widget,
+ GduDrive *drive,
+ Reason *out_reason)
+{
+ gboolean ret;
+ guint64 largest_segment;
+ gboolean whole_disk_is_uninitialized;
+ Reason reason;
+ GduDevice *d;
+
+ ret = FALSE;
+ d = NULL;
+ reason = REASON_INSUFFICIENT_SPACE;
+
+ d = gdu_presentable_get_device (GDU_PRESENTABLE (drive));
+ if (d != NULL && gdu_device_is_linux_dmmp_component (d)) {
+ ret = FALSE;
+ reason = REASON_MULTIPATH_COMPONENT;
+ goto out;
+ }
+
+ if (gdu_drive_can_create_volume (drive,
+ &whole_disk_is_uninitialized,
+ &largest_segment,
+ NULL, /* total_free */
+ NULL)) {
+ if (largest_segment >= widget->priv->component_size) {
+ ret = TRUE;
+ }
+ }
+
+ out:
+#if 0
+ g_debug ("is_drive_selectable (%s): %d %" G_GUINT64_FORMAT " (%d %d) ...",
+ d != NULL ? gdu_device_get_device_file (d) : "(not set)",
+ whole_disk_is_uninitialized,
+ largest_segment,
+ reason,
+ ret);
+#endif
+
+ if (d != NULL)
+ g_object_unref (d);
+
+ if (out_reason != NULL)
+ *out_reason = reason;
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
static gboolean
drive_is_selected (GduDiskSelectionWidget *widget,
GduPresentable *drive)
@@ -461,7 +520,7 @@ toggle_data_func (GtkCellLayout *cell_layout,
is_visible = FALSE;
is_toggled = FALSE;
if (GDU_IS_DRIVE (p)) {
- is_visible = TRUE;
+ is_visible = is_drive_selectable (widget, GDU_DRIVE (p), NULL);
is_toggled = drive_is_selected (widget, p);
}
@@ -534,6 +593,41 @@ on_disk_toggled (GtkCellRendererToggle *renderer,
/* ---------------------------------------------------------------------------------------------------- */
static void
+icon_data_func (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (user_data);
+ GduPresentable *p;
+ GIcon *icon;
+ gboolean sensitive;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+ GDU_POOL_TREE_MODEL_COLUMN_ICON, &icon,
+ -1);
+
+ sensitive = TRUE;
+ if (p != NULL && GDU_IS_DRIVE (p))
+ sensitive = is_drive_selectable (widget, GDU_DRIVE (p), NULL);
+
+ g_object_set (renderer,
+ "gicon", icon,
+ "sensitive", sensitive,
+ NULL);
+
+ if (icon != NULL)
+ g_object_unref (icon);
+ if (p != NULL)
+ g_object_unref (p);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
disk_name_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *renderer,
GtkTreeModel *tree_model,
@@ -549,14 +643,20 @@ disk_name_data_func (GtkCellLayout *cell_layout,
GdkColor desc_gdk_color = {0};
gchar *desc_color;
GtkStateType state;
+ gboolean sensitive;
+ GduPresentable *p;
tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->tree_view));
gtk_tree_model_get (tree_model,
iter,
+ GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
GDU_POOL_TREE_MODEL_COLUMN_NAME, &name,
GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME, &vpd_name,
-1);
+ sensitive = TRUE;
+ if (p != NULL && GDU_IS_DRIVE (p))
+ sensitive = is_drive_selectable (widget, GDU_DRIVE (p), NULL);
/* This color business shouldn't be this hard... */
style = gtk_widget_get_style (GTK_WIDGET (widget->priv->tree_view));
@@ -581,42 +681,61 @@ disk_name_data_func (GtkCellLayout *cell_layout,
(desc_gdk_color.green >> 8),
(desc_gdk_color.blue >> 8));
- markup = g_strdup_printf ("<small><b>%s</b>\n"
- "<span fgcolor=\"%s\">%s</span></small>",
- name,
- desc_color,
- vpd_name);
+ if (sensitive) {
+ markup = g_strdup_printf ("<small><b>%s</b>\n"
+ "<span fgcolor=\"%s\">%s</span></small>",
+ name,
+ desc_color,
+ vpd_name);
+ } else {
+ markup = g_strdup_printf ("<small><b>%s</b>\n"
+ "%s</small>",
+ name,
+ vpd_name);
+ }
g_object_set (renderer,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE,
"ellipsize-set", TRUE,
"markup", markup,
+ "sensitive", sensitive,
NULL);
g_free (name);
g_free (vpd_name);
g_free (markup);
g_free (desc_color);
+
+ if (p != NULL)
+ g_object_unref (p);
}
/* ---------------------------------------------------------------------------------------------------- */
+typedef struct {
+ GduDiskSelectionWidget *widget;
+ guint num_available_disks;
+ guint64 largest_segment_for_all;
+} CountData;
+
static gboolean
count_num_available_disks_func (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
- gpointer data)
+ gpointer user_data)
{
GduPresentable *p;
- guint *num_available_disks = data;
+ CountData *data = user_data;
gtk_tree_model_get (model,
iter,
GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
-1);
- if (GDU_IS_DRIVE (p))
- *num_available_disks = *num_available_disks + 1;
+ if (GDU_IS_DRIVE (p)) {
+ if (is_drive_selectable (data->widget, GDU_DRIVE (p), NULL))
+ data->num_available_disks = data->num_available_disks + 1;
+ }
g_object_unref (p);
@@ -627,10 +746,10 @@ static gboolean
find_largest_segment_for_all_func (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
- gpointer data)
+ gpointer user_data)
{
GduPresentable *p;
- guint64 *largest_segment_for_all = data;
+ CountData *data = user_data;
gtk_tree_model_get (model,
iter,
@@ -640,14 +759,14 @@ find_largest_segment_for_all_func (GtkTreeModel *model,
if (GDU_IS_DRIVE (p)) {
guint64 largest_segment;
- g_warn_if_fail (gdu_drive_has_unallocated_space (GDU_DRIVE (p),
- NULL,
- &largest_segment,
- NULL, /* total_free */
- NULL));
-
- if (largest_segment > *largest_segment_for_all)
- *largest_segment_for_all = largest_segment;
+ if (gdu_drive_can_create_volume (GDU_DRIVE (p),
+ NULL,
+ &largest_segment,
+ NULL, /* total_free */
+ NULL)) {
+ if (largest_segment > data->largest_segment_for_all)
+ data->largest_segment_for_all = largest_segment;
+ }
}
@@ -664,54 +783,54 @@ get_sizes (GduDiskSelectionWidget *widget,
guint64 *out_largest_segment_for_all)
{
guint num_disks;
- guint num_available_disks;
+ CountData data;
guint64 largest_segment_for_selected;
- guint64 largest_segment_for_all;
GList *l;
num_disks = 0;
- num_available_disks = 0;
largest_segment_for_selected = G_MAXUINT64;
- largest_segment_for_all = 0;
+ data.widget = widget;
+ data.num_available_disks = 0;
+ data.largest_segment_for_all = 0;
for (l = widget->priv->selected_drives; l != NULL; l = l->next) {
GduPresentable *p = GDU_PRESENTABLE (l->data);
guint64 largest_segment;
gboolean whole_disk_is_uninitialized;
- g_warn_if_fail (gdu_drive_has_unallocated_space (GDU_DRIVE (p),
- &whole_disk_is_uninitialized,
- &largest_segment,
- NULL, /* total_free */
- NULL));
+ if (gdu_drive_can_create_volume (GDU_DRIVE (p),
+ &whole_disk_is_uninitialized,
+ &largest_segment,
+ NULL, /* total_free */
+ NULL)) {
+ if (largest_segment < largest_segment_for_selected)
+ largest_segment_for_selected = largest_segment;
- if (largest_segment < largest_segment_for_selected)
- largest_segment_for_selected = largest_segment;
-
- num_disks++;
+ num_disks++;
+ }
}
if (largest_segment_for_selected == G_MAXUINT64)
largest_segment_for_selected = 0;
gtk_tree_model_foreach (widget->priv->model,
count_num_available_disks_func,
- &num_available_disks);
+ &data);
gtk_tree_model_foreach (widget->priv->model,
find_largest_segment_for_all_func,
- &largest_segment_for_all);
+ &data);
if (out_num_disks != NULL)
*out_num_disks = num_disks;
if (out_num_available_disks != NULL)
- *out_num_available_disks = num_available_disks;
+ *out_num_available_disks = data.num_available_disks;
if (out_largest_segment_for_selected != NULL)
*out_largest_segment_for_selected = largest_segment_for_selected;
if (out_largest_segment_for_all != NULL)
- *out_largest_segment_for_all = largest_segment_for_all;
+ *out_largest_segment_for_all = data.largest_segment_for_all;
}
static void
@@ -725,149 +844,220 @@ notes_data_func (GtkCellLayout *cell_layout,
GduPresentable *p;
gchar *markup;
gchar *s;
+ gboolean sensitive;
+ GduDevice *d;
+ gboolean can_create_volume;
+ guint64 largest_segment;
+ gboolean whole_disk_is_uninitialized;
+ guint num_partitions;
+ gboolean is_partitionable;
+ gboolean is_partitioned;
+ guint64 total_free;
+ guint64 remaining_size;
+ gboolean is_selectable;
+ Reason reason;
+ gchar *strsize;
+ gchar *rem_strsize;
+
+ d = NULL;
+ markup = NULL;
+ sensitive = TRUE;
gtk_tree_model_get (tree_model,
iter,
GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
-1);
- if (GDU_IS_DRIVE (p)) {
- GduDevice *d;
- guint64 largest_segment;
- gboolean whole_disk_is_uninitialized;
- guint num_partitions;
- gboolean is_partitioned;
- guint64 total_free;
- guint64 remaining_size;
-
- d = gdu_presentable_get_device (p);
-
- num_partitions = 0;
- is_partitioned = FALSE;
- remaining_size = 0;
- if (gdu_device_is_partition_table (d)) {
- is_partitioned = TRUE;
- num_partitions = gdu_device_partition_table_get_count (d);
- }
+ if (!GDU_IS_DRIVE (p))
+ goto out;
- g_warn_if_fail (gdu_drive_has_unallocated_space (GDU_DRIVE (p),
- &whole_disk_is_uninitialized,
- &largest_segment,
- &total_free,
- NULL));
+ d = gdu_presentable_get_device (p);
+
+ num_partitions = 0;
+ is_partitioned = FALSE;
+ is_partitionable = TRUE;
+ remaining_size = 0;
+ if (d != NULL && gdu_device_is_partition_table (d)) {
+ is_partitioned = TRUE;
+ num_partitions = gdu_device_partition_table_get_count (d);
+ }
- remaining_size = total_free - widget->priv->component_size;
+ /* TODO: probably want a vfunc for this */
+ if (GDU_IS_LINUX_LVM2_VOLUME_GROUP (p))
+ is_partitionable = FALSE;
- if (drive_is_selected (widget, p)) {
- gchar *strsize;
- gchar *rem_strsize;
+ can_create_volume = gdu_drive_can_create_volume (GDU_DRIVE (p),
+ &whole_disk_is_uninitialized,
+ &largest_segment,
+ &total_free,
+ NULL);
+
+ is_selectable = is_drive_selectable (widget, GDU_DRIVE (p), &reason);
+ sensitive = is_selectable;
+
+ remaining_size = total_free - widget->priv->component_size;
+
+ /* handle when the drive is not selectable */
+ if (!is_selectable) {
+ switch (reason) {
+ case REASON_INSUFFICIENT_SPACE:
+ if (largest_segment < SIZE_EPSILON) {
+ /* Translators: Shown when the device is not selectable because
+ * there is no free space.
+ */
+ markup = g_strdup_printf (_("No free space."));
+ } else {
+ strsize = gdu_util_get_size_for_display (widget->priv->component_size, FALSE, FALSE);
+ rem_strsize = gdu_util_get_size_for_display (largest_segment, FALSE, FALSE);
+ /* Translators: Shown when device is unselectable because not enough space is available.
+ * First %s (e.g. '10 GB') is how much space is needed.
+ * Second %s (e.g. '5 GB') is how much space is available.
+ */
+ markup = g_strdup_printf (_("Insufficient space: %s is needed but largest contiguous free block is %s."),
+ strsize,
+ rem_strsize);
+ g_free (strsize);
+ g_free (rem_strsize);
+ }
+ break;
+ case REASON_MULTIPATH_COMPONENT:
+ /* Translators: Shown when the device is unselectable because it is a multipath component. */
+ markup = g_strdup_printf (_("Cannot select multipath component"));
+ break;
+ }
+ goto out;
+ }
- strsize = gdu_util_get_size_for_display (widget->priv->component_size, FALSE, FALSE);
- rem_strsize = gdu_util_get_size_for_display (remaining_size, FALSE, FALSE);
+ /* drive is selectable */
+ if (drive_is_selected (widget, p)) {
+ strsize = gdu_util_get_size_for_display (widget->priv->component_size, FALSE, FALSE);
+ rem_strsize = gdu_util_get_size_for_display (remaining_size, FALSE, FALSE);
- if (whole_disk_is_uninitialized) {
- if (widget->priv->component_size == 0) {
+ if (whole_disk_is_uninitialized) {
+ if (widget->priv->component_size < SIZE_EPSILON) {
+ /* Translators: This is shown in the details column */
+ markup = g_strdup (_("The disk will be partitioned and a partition will be created"));
+ } else {
+ if (remaining_size < SIZE_EPSILON) {
+ /* Translators: This is shown in the Details column.
+ * First %s is the component size e.g. '42 GB'.
+ */
+ markup = g_strdup_printf (_("The disk will be partitioned and a %s partition "
+ "will be created. "
+ "Afterwards no space will be available."),
+ strsize);
+ } else {
+ /* Translators: This is shown in the Details column.
+ * First %s is the component size e.g. '42 GB'.
+ * Second %s is the remaining free space after the operation.
+ */
+ markup = g_strdup_printf (_("The disk will be partitioned and a %s partition "
+ "will be created. "
+ "Afterwards %s will be available."),
+ strsize,
+ rem_strsize);
+ }
+ }
+ } else {
+ if (widget->priv->component_size < SIZE_EPSILON) {
+ if (is_partitionable) {
/* Translators: This is shown in the details column */
- markup = g_strdup (_("The disk will be partitioned and a partition will be created"));
+ markup = g_strdup (_("A partition will be created"));
} else {
- if (remaining_size == 0) {
+ /* Translators: This is shown in the details column */
+ markup = g_strdup (_("A volume will be created"));
+ }
+ } else {
+ if (remaining_size < SIZE_EPSILON) {
+ if (is_partitionable) {
/* Translators: This is shown in the Details column.
* First %s is the component size e.g. '42 GB'.
*/
- markup = g_strdup_printf (_("The disk will be partitioned and a %s partition "
- "will be created. "
+ markup = g_strdup_printf (_("A %s partition will be created. "
"Afterwards no space will be available."),
strsize);
} else {
/* Translators: This is shown in the Details column.
* First %s is the component size e.g. '42 GB'.
- * Second %s is the remaining free space after the operation.
*/
- markup = g_strdup_printf (_("The disk will be partitioned and a %s partition "
- "will be created. "
- "Afterwards %s will be available."),
- strsize,
- rem_strsize);
+ markup = g_strdup_printf (_("A %s volume will be created. "
+ "Afterwards no space will be available."),
+ strsize);
}
- }
- } else {
- if (widget->priv->component_size == 0) {
- /* Translators: This is shown in the details column */
- markup = g_strdup (_("A partition will be created"));
} else {
- if (remaining_size == 0) {
+ if (is_partitionable) {
/* Translators: This is shown in the Details column.
* First %s is the component size e.g. '42 GB'.
+ * Second %s is the remaining free space after the operation.
*/
markup = g_strdup_printf (_("A %s partition will be created. "
- "Afterwards no space will be available."),
- strsize);
+ "Afterwards %s will be available."),
+ strsize,
+ rem_strsize);
} else {
/* Translators: This is shown in the Details column.
* First %s is the component size e.g. '42 GB'.
* Second %s is the remaining free space after the operation.
*/
- markup = g_strdup_printf (_("A %s partition will be created. "
+ markup = g_strdup_printf (_("A %s volume will be created. "
"Afterwards %s will be available."),
strsize,
rem_strsize);
}
}
}
- g_free (strsize);
- g_free (rem_strsize);
-
- } else {
- gchar *strsize;
+ }
+ g_free (strsize);
+ g_free (rem_strsize);
+ } else {
+ gchar *strsize;
- strsize = gdu_util_get_size_for_display (largest_segment, FALSE, FALSE);
+ /* Drive is not selected */
- if (whole_disk_is_uninitialized) {
+ strsize = gdu_util_get_size_for_display (largest_segment, FALSE, FALSE);
+ if (whole_disk_is_uninitialized) {
+ /* Translators: This is shown in the Details column.
+ * %s is the component size e.g. '42 GB'.
+ */
+ markup = g_strdup_printf (_("Whole disk is uninitialized. %s available for use"),
+ strsize);
+ } else {
+ if (!is_partitioned) {
/* Translators: This is shown in the Details column.
* %s is the component size e.g. '42 GB'.
*/
- markup = g_strdup_printf (_("Whole disk is uninitialized. %s available for use"),
- strsize);
+ markup = g_strdup_printf (_("%s available for use"), strsize);
} else {
- if (!is_partitioned) {
+ if (num_partitions == 0) {
/* Translators: This is shown in the Details column.
* %s is the component size e.g. '42 GB'.
*/
- markup = g_strdup_printf (_("%s available for use"), strsize);
+ markup = g_strdup_printf (_("The disk has no partitions. "
+ "%s available for use"),
+ strsize);
} else {
- if (num_partitions == 0) {
- /* Translators: This is shown in the Details column.
- * %s is the component size e.g. '42 GB'.
- */
- markup = g_strdup_printf (_("The disk has no partitions. "
- "%s available for use"),
- strsize);
- } else {
- s = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
- "The disk has %d partition",
- "The disk has %d partitions",
- num_partitions),
- num_partitions);
- /* Translators: This is shown in the Details column.
- * First %s is the dngettext() result of "The disk has %d partitions.".
- * Second %s is the component size e.g. '42 GB'.
- */
- markup = g_strdup_printf (_("%s. Largest contiguous free block is %s"),
- s,
- strsize);
- g_free (s);
- }
+ s = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+ "The disk has %d partition",
+ "The disk has %d partitions",
+ num_partitions),
+ num_partitions);
+ /* Translators: This is shown in the Details column.
+ * First %s is the dngettext() result of "The disk has %d partitions.".
+ * Second %s is the component size e.g. '42 GB'.
+ */
+ markup = g_strdup_printf (_("%s. Largest contiguous free block is %s"),
+ s,
+ strsize);
+ g_free (s);
}
}
-
- g_free (strsize);
}
-
- g_object_unref (d);
- } else {
- markup = g_strdup ("");
+ g_free (strsize);
}
+ out:
+ if (markup == NULL)
+ markup = g_strdup ("");
s = g_strconcat ("<small>",
markup,
"</small>",
@@ -875,15 +1065,20 @@ notes_data_func (GtkCellLayout *cell_layout,
g_object_set (renderer,
"markup", s,
"wrap-width", DETAILS_WIDTH - DETAILS_MARGIN,
+ "sensitive", sensitive,
NULL);
g_free (s);
g_free (markup);
g_object_unref (p);
+
+ if (d != NULL)
+ g_object_unref (d);
}
/* ---------------------------------------------------------------------------------------------------- */
+#if 0
static gboolean
model_visible_func (GtkTreeModel *model,
GtkTreeIter *iter,
@@ -903,21 +1098,9 @@ model_visible_func (GtkTreeModel *model,
iter,
GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
-1);
-
if (p != NULL) {
if (GDU_IS_DRIVE (p)) {
- guint64 largest_segment;
- gboolean whole_disk_is_uninitialized;
-
- if (gdu_drive_has_unallocated_space (GDU_DRIVE (p),
- &whole_disk_is_uninitialized,
- &largest_segment,
- NULL, /* total_free */
- NULL)) {
- if (largest_segment >= widget->priv->component_size) {
- ret = TRUE;
- }
- }
+ ret = is_drive_selectable (widget, GDU_DRIVE (p));
} else {
ret = TRUE;
}
@@ -927,7 +1110,7 @@ model_visible_func (GtkTreeModel *model,
return ret;
}
-
+#endif
/* ---------------------------------------------------------------------------------------------------- */
@@ -946,16 +1129,17 @@ gdu_disk_selection_widget_constructed (GObject *object)
g_ptr_array_add (pools, widget->priv->pool);
model = GTK_TREE_MODEL (gdu_pool_tree_model_new (pools,
NULL,
- GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES |
- GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES));
+ GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES /* | GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES */));
g_ptr_array_unref (pools);
widget->priv->model = gtk_tree_model_filter_new (model, NULL);
g_object_unref (model);
+#if 0
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (widget->priv->model),
model_visible_func,
widget,
NULL);
+#endif
tree_view = gtk_tree_view_new_with_model (widget->priv->model);
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
@@ -984,10 +1168,11 @@ gdu_disk_selection_widget_constructed (GObject *object)
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer, FALSE);
- gtk_tree_view_column_set_attributes (column,
- renderer,
- "gicon", GDU_POOL_TREE_MODEL_COLUMN_ICON,
- NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+ renderer,
+ icon_data_func,
+ widget,
+ NULL);
g_object_set (renderer,
"stock-size", GTK_ICON_SIZE_MENU,
NULL);
@@ -1156,10 +1341,11 @@ gdu_disk_selection_widget_get_num_available_disks (GduDiskSelectionWidget *widge
{
guint num_available_disks;
- num_available_disks = 0;
- gtk_tree_model_foreach (widget->priv->model,
- count_num_available_disks_func,
- &num_available_disks);
+ get_sizes (widget,
+ NULL,
+ &num_available_disks,
+ NULL,
+ NULL);
return num_available_disks;
}
diff --git a/src/gdu-gtk/gdu-pool-tree-model.c b/src/gdu-gtk/gdu-pool-tree-model.c
index ae76e84..d7453f2 100644
--- a/src/gdu-gtk/gdu-pool-tree-model.c
+++ b/src/gdu-gtk/gdu-pool-tree-model.c
@@ -495,7 +495,7 @@ should_include_presentable (GduPoolTreeModel *model,
if (GDU_IS_DRIVE (presentable)) {
if ((model->priv->flags & GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES) &&
- (!gdu_drive_has_unallocated_space (GDU_DRIVE (presentable), NULL, NULL, NULL, NULL)))
+ (!gdu_drive_can_create_volume (GDU_DRIVE (presentable), NULL, NULL, NULL, NULL)))
goto out;
}
diff --git a/src/gdu/gdu-drive.c b/src/gdu/gdu-drive.c
index a841a6c..ad56f61 100644
--- a/src/gdu/gdu-drive.c
+++ b/src/gdu/gdu-drive.c
@@ -68,11 +68,22 @@ G_DEFINE_TYPE_WITH_CODE (GduDrive, gdu_drive, G_TYPE_OBJECT,
static void device_job_changed (GduDevice *device, gpointer user_data);
static void device_changed (GduDevice *device, gpointer user_data);
-static gboolean gdu_drive_has_unallocated_space_real (GduDrive *drive,
- gboolean *out_whole_disk_is_unitialized,
- guint64 *out_largest_segment,
- guint64 *out_total_free,
- GduPresentable **out_presentable);
+static gboolean gdu_drive_can_create_volume_real (GduDrive *drive,
+ gboolean *out_is_uninitialized,
+ guint64 *out_largest_contiguous_free_segment,
+ guint64 *out_total_free,
+ GduPresentable **out_presentable);
+
+static void gdu_drive_create_volume_real (GduDrive *drive,
+ guint64 size,
+ const gchar *name,
+ GduCreateVolumeFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static GduVolume *gdu_drive_create_volume_finish_real (GduDrive *drive,
+ GAsyncResult *res,
+ GError **error);
static void
gdu_drive_finalize (GduDrive *drive)
@@ -106,7 +117,9 @@ gdu_drive_class_init (GduDriveClass *klass)
obj_class->finalize = (GObjectFinalizeFunc) gdu_drive_finalize;
- klass->has_unallocated_space = gdu_drive_has_unallocated_space_real;
+ klass->can_create_volume = gdu_drive_can_create_volume_real;
+ klass->create_volume = gdu_drive_create_volume_real;
+ klass->create_volume_finish = gdu_drive_create_volume_finish_real;
g_type_class_add_private (klass, sizeof (GduDrivePrivate));
}
@@ -200,26 +213,25 @@ gdu_drive_deactivate (GduDrive *drive,
}
/**
- * gdu_drive_has_unallocated_space:
+ * gdu_drive_can_create_volume:
* @drive: A #GduDrive.
- * @out_whole_disk_is_unitialized: Return location for whether @drive is uninitialized or %NULL.
+ * @out_is_uninitialized: Return location for whether @drive is uninitialized or %NULL.
* @out_largest_segment: Return location for biggest contigious free block of @drive or %NULL.
* @out_total_free: Return location for total amount of free space on @drive or %NULL.
* @out_presentable: Return location for the presentable that represents free space or %NULL. Free
* with g_object_unref().
*
- * This method computes the largest contigious free block of
- * unallocated space on @drive.
+ * This method checks if a new volume can be created on @drive.
*
* If @drive uses removable media and there is no media inserted,
* %FALSE is returned.
*
* If @drive appears to be completely uninitialized (such as a hard
- * disk full of zeros), @out_whole_disk_is_unitialized is set to
- * %TRUE, the size of the media/disk is returned in
- * @out_largest_segment and %TRUE is returned. Note that this can
- * also happen if @drive contains signatures unknown to the operating system
- * so be careful.
+ * disk full of zeros), @out_is_unitialized is set to %TRUE, the size
+ * of the media/disk is returned in @out_largest_segment and %TRUE is
+ * returned. Note that this can also happen if @drive contains
+ * signatures unknown to the operating system so be careful and always
+ * prompt the user.
*
* If the disk is partitioned and unallocated space exists but no more
* partitions can be created (due to e.g. four primary partitions on a
@@ -230,22 +242,23 @@ gdu_drive_deactivate (GduDrive *drive,
* #GduVolumeHole (if the disk is partitioned and has free space) or
* the #GduDrive (if the disk is uninitialized).
*
+ * You can use gdu_drive_create_volume() to create a volume.
+ *
* Returns: %TRUE if @drive has unallocated space, %FALSE otherwise.
*/
gboolean
-gdu_drive_has_unallocated_space (GduDrive *drive,
- gboolean *out_whole_disk_is_unitialized,
- guint64 *out_largest_segment,
- guint64 *out_total_free,
- GduPresentable **out_presentable)
+gdu_drive_can_create_volume (GduDrive *drive,
+ gboolean *out_is_uninitialized,
+ guint64 *out_largest_contiguous_free_segment,
+ guint64 *out_total_free,
+ GduPresentable **out_presentable)
{
GduDriveClass *klass = GDU_DRIVE_GET_CLASS (drive);
-
- return klass->has_unallocated_space (drive,
- out_whole_disk_is_unitialized,
- out_largest_segment,
- out_total_free,
- out_presentable);
+ return klass->can_create_volume (drive,
+ out_is_uninitialized,
+ out_largest_contiguous_free_segment,
+ out_total_free,
+ out_presentable);
}
/**
@@ -326,15 +339,15 @@ gdu_drive_count_mbr_partitions (GduDrive *drive,
static gboolean
-gdu_drive_has_unallocated_space_real (GduDrive *drive,
- gboolean *out_whole_disk_is_unitialized,
- guint64 *out_largest_segment,
- guint64 *out_total_free,
- GduPresentable **out_presentable)
+gdu_drive_can_create_volume_real (GduDrive *drive,
+ gboolean *out_is_unitialized,
+ guint64 *out_largest_contiguous_free_segment,
+ guint64 *out_total_free,
+ GduPresentable **out_presentable)
{
GduDevice *device;
GduPool *pool;
- guint64 largest_segment;
+ guint64 largest_contiguous_free_segment;
guint64 total_free;
gboolean whole_disk_uninitialized;
GList *enclosed_presentables;
@@ -344,7 +357,7 @@ gdu_drive_has_unallocated_space_real (GduDrive *drive,
guint64 size;
GduPresentable *pres;
- largest_segment = 0;
+ largest_contiguous_free_segment = 0;
total_free = 0;
whole_disk_uninitialized = FALSE;
ret = FALSE;
@@ -371,7 +384,7 @@ gdu_drive_has_unallocated_space_real (GduDrive *drive,
*/
if (!gdu_device_is_partition_table (device) && strlen (gdu_device_id_get_usage (device)) == 0) {
whole_disk_uninitialized = TRUE;
- largest_segment = gdu_device_get_size (device);
+ largest_contiguous_free_segment = gdu_device_get_size (device);
total_free = gdu_device_get_size (device);
ret = TRUE;
pres = GDU_PRESENTABLE (drive);
@@ -389,8 +402,8 @@ gdu_drive_has_unallocated_space_real (GduDrive *drive,
if (GDU_IS_VOLUME_HOLE (ep)) {
size = gdu_presentable_get_size (ep);
- if (size > largest_segment) {
- largest_segment = size;
+ if (size > largest_contiguous_free_segment) {
+ largest_contiguous_free_segment = size;
pres = ep;
}
@@ -416,8 +429,8 @@ gdu_drive_has_unallocated_space_real (GduDrive *drive,
if (GDU_IS_VOLUME_HOLE (lep)) {
size = gdu_presentable_get_size (lep);
- if (size > largest_segment) {
- largest_segment = size;
+ if (size > largest_contiguous_free_segment) {
+ largest_contiguous_free_segment = size;
pres = lep;
}
@@ -433,10 +446,10 @@ gdu_drive_has_unallocated_space_real (GduDrive *drive,
g_list_foreach (enclosed_presentables, (GFunc) g_object_unref, NULL);
g_list_free (enclosed_presentables);
- ret = (largest_segment > 0);
+ ret = (largest_contiguous_free_segment > 0);
/* Now igure out if the partition table is full (e.g. four primary partitions already) and
- * return %FALSE and non-zero @out_largest_segment
+ * return %FALSE and non-zero @out_largest_contiguous_free_segment
*/
if (g_strcmp0 (gdu_device_partition_table_get_scheme (device), "mbr") == 0 &&
gdu_device_partition_table_get_count (device) == 4 &&
@@ -450,14 +463,14 @@ gdu_drive_has_unallocated_space_real (GduDrive *drive,
if (pool != NULL)
g_object_unref (pool);
- if (out_largest_segment != NULL)
- *out_largest_segment = largest_segment;
+ if (out_largest_contiguous_free_segment != NULL)
+ *out_largest_contiguous_free_segment = largest_contiguous_free_segment;
if (out_total_free != NULL)
*out_total_free = total_free;
- if (out_whole_disk_is_unitialized != NULL)
- *out_whole_disk_is_unitialized = whole_disk_uninitialized;
+ if (out_is_unitialized != NULL)
+ *out_is_unitialized = whole_disk_uninitialized;
if (out_presentable != NULL) {
*out_presentable = (pres != NULL ? g_object_ref (pres) : NULL);
@@ -1094,3 +1107,309 @@ _gdu_drive_rewrite_enclosing_presentable (GduDrive *drive)
out:
;
}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+create_volume_partition_create_cb (GduDevice *device,
+ gchar *created_device_object_path,
+ GError *error,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ } else {
+ GduDevice *d;
+ GduPool *pool;
+ GduPresentable *volume;
+
+ pool = gdu_device_get_pool (device);
+ d = gdu_pool_get_by_object_path (pool, created_device_object_path);
+ g_assert (d != NULL);
+
+ volume = gdu_pool_get_volume_by_device (pool, d);
+ g_assert (volume != NULL);
+
+ g_simple_async_result_set_op_res_gpointer (simple, volume, g_object_unref);
+
+ g_object_unref (pool);
+ g_object_unref (d);
+ }
+ g_simple_async_result_complete_in_idle (simple);
+}
+
+static void
+gdu_drive_create_volume_real_internal (GduDrive *drive,
+ guint64 size,
+ const gchar *name,
+ GduCreateVolumeFlags flags,
+ GSimpleAsyncResult *simple);
+
+static void
+create_volume_partition_table_create_cb (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete_in_idle (simple);
+ g_error_free (error);
+ } else {
+ GduDrive *drive;
+ guint64 size;
+ const gchar *name;
+ GduCreateVolumeFlags flags;
+
+ drive = GDU_DRIVE (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+ size = (* ((guint64 *) g_object_get_data (G_OBJECT (simple), "gdu-size")));
+ name = g_object_get_data (G_OBJECT (simple), "gdu-name");
+ flags = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (simple), "gdu-flags"));
+
+ /* now that we have a partition table... try creating the volume again */
+ gdu_drive_create_volume_real_internal (drive,
+ size,
+ name,
+ flags,
+ simple);
+
+ g_object_unref (drive);
+ }
+}
+
+static void
+gdu_drive_create_volume_real (GduDrive *drive,
+ guint64 size,
+ const gchar *name,
+ GduCreateVolumeFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (GDU_IS_DRIVE (drive));
+
+ simple = g_simple_async_result_new (G_OBJECT (drive),
+ callback,
+ user_data,
+ gdu_drive_create_volume);
+
+ g_object_set_data_full (G_OBJECT (simple), "gdu-size", g_memdup (&size, sizeof (guint64)), g_free);
+ g_object_set_data_full (G_OBJECT (simple), "gdu-name", g_strdup (name), g_free);
+ g_object_set_data (G_OBJECT (simple), "gdu-flags", GINT_TO_POINTER (flags));
+
+ gdu_drive_create_volume_real_internal (drive,
+ size,
+ name,
+ flags,
+ simple);
+}
+
+static void
+gdu_drive_create_volume_real_internal (GduDrive *drive,
+ guint64 size,
+ const gchar *name,
+ GduCreateVolumeFlags flags,
+ GSimpleAsyncResult *simple)
+{
+ GduPresentable *p;
+ GduDevice *d;
+ gboolean whole_disk_is_uninitialized;
+ guint64 largest_segment;
+
+ if (!gdu_drive_can_create_volume (drive,
+ &whole_disk_is_uninitialized,
+ &largest_segment,
+ NULL, /* total_free */
+ &p)) {
+ g_simple_async_result_set_error (simple,
+ GDU_ERROR,
+ GDU_ERROR_FAILED,
+ "Insufficient space");
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ goto out;
+ }
+
+ g_assert (p != NULL);
+
+ d = gdu_presentable_get_device (GDU_PRESENTABLE (drive));
+
+ if (GDU_IS_VOLUME_HOLE (p)) {
+ guint64 offset;
+ const gchar *scheme;
+ const gchar *type;
+ gchar *label;
+
+ offset = gdu_presentable_get_offset (p);
+
+ scheme = gdu_device_partition_table_get_scheme (d);
+ type = "";
+ label = NULL;
+ if (g_strcmp0 (scheme, "mbr") == 0) {
+ if (flags & GDU_CREATE_VOLUME_FLAGS_LINUX_MD) {
+ type = "0xfd";
+ } else if (flags & GDU_CREATE_VOLUME_FLAGS_LINUX_LVM2) {
+ type = "0x8e";
+ }
+ } else if (g_strcmp0 (scheme, "gpt") == 0) {
+ if (flags & GDU_CREATE_VOLUME_FLAGS_LINUX_MD) {
+ type = "A19D880F-05FC-4D3B-A006-743F0F84911E";
+ /* Limited to 36 UTF-16LE characters according to on-disk format..
+ * Since a RAID array name is limited to 32 chars this should fit */
+ if (name != NULL)
+ label = g_strdup_printf ("RAID: %s", name);
+ else
+ label = g_strdup_printf ("RAID component");
+ } else if (flags & GDU_CREATE_VOLUME_FLAGS_LINUX_LVM2) {
+ type = "E6D6D379-F507-44C2-A23C-238F2A3DF928";
+ /* Limited to 36 UTF-16LE characters according to on-disk format..
+ * TODO: ensure name is shorter than or equal to 32 characters */
+ if (name != NULL)
+ label = g_strdup_printf ("LVM2: %s", name);
+ else
+ label = g_strdup_printf ("LVM2 component");
+ }
+ } else if (g_strcmp0 (scheme, "apt") == 0) {
+ type = "Apple_Unix_SVR2";
+ if (flags & GDU_CREATE_VOLUME_FLAGS_LINUX_MD) {
+ if (name != NULL)
+ label = g_strdup_printf ("RAID: %s", name);
+ else
+ label = g_strdup_printf ("RAID component");
+ } else if (flags & GDU_CREATE_VOLUME_FLAGS_LINUX_LVM2) {
+ if (name != NULL)
+ label = g_strdup_printf ("LVM2: %s", name);
+ else
+ label = g_strdup_printf ("LVM2 component");
+ }
+ }
+
+ gdu_device_op_partition_create (d,
+ offset,
+ size,
+ type,
+ label != NULL ? label : "",
+ NULL,
+ "",
+ "",
+ "",
+ FALSE,
+ create_volume_partition_create_cb,
+ simple);
+ g_free (label);
+
+ } else {
+
+ /* otherwise the whole disk must be uninitialized... */
+ g_assert (whole_disk_is_uninitialized);
+
+ /* so create a partition table...
+ * (TODO: take a flag to determine what kind of partition table to create)
+ */
+ gdu_device_op_partition_table_create (d,
+ "mbr",
+ create_volume_partition_table_create_cb,
+ simple);
+ }
+
+ out:
+ if (d != NULL)
+ g_object_unref (d);
+ if (p != NULL)
+ g_object_unref (p);
+}
+
+static GduVolume *
+gdu_drive_create_volume_finish_real (GduDrive *drive,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GduVolume *ret;
+
+ g_return_val_if_fail (GDU_IS_DRIVE (drive), NULL);
+ g_return_val_if_fail (res != NULL, NULL);
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == gdu_drive_create_volume);
+
+ ret = NULL;
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ ret = GDU_VOLUME (g_simple_async_result_get_op_res_gpointer (simple));
+
+ out:
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * gdu_drive_create_volume:
+ * @drive: A #GduDrive.
+ * @size: The size of the volume to create.
+ * @name: A name for the volume.
+ * @flags: Flags describing what kind of volume to create
+ * @callback: Function to call when the result is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * High-level method for creating a new volume on @drive of size @size
+ * using @name and @flags as influential hints.
+ *
+ * Depending on the actual type of @drive, different things may happen
+ * - if @drive represents a partitioned drive, then a new partition
+ * will be created (and if the partitioning scheme supports partition
+ * labels @name will be used as the label). If @drive is completely
+ * uninitialized, it may (or may not) be partitioned.
+ *
+ * If @drive represents a LVM2 volume group, a logical volume may be
+ * created (with @name being used as LV name).
+ *
+ * This is an asynchronous operation. When the result of the operation
+ * is ready, @callback will be invoked.
+ */
+void
+gdu_drive_create_volume (GduDrive *drive,
+ guint64 size,
+ const gchar *name,
+ GduCreateVolumeFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GduDriveClass *klass = GDU_DRIVE_GET_CLASS (drive);
+ klass->create_volume (drive,
+ size,
+ name,
+ flags,
+ callback,
+ user_data);
+}
+
+/**
+ * gdu_drive_create_volume_finish:
+ * @drive: A #GduDrive.
+ * @res: A #GAsyncResult.
+ * @error: A #GError or %NULL.
+ *
+ * Finishes an operation started with gdu_drive_create_volume().
+ *
+ * Returns: A #GduVolume for the created volume or %NULL if @error is
+ * set. The returned object must be freed with g_object_unref().
+ */
+GduVolume *
+gdu_drive_create_volume_finish (GduDrive *drive,
+ GAsyncResult *res,
+ GError **error)
+{
+ GduDriveClass *klass = GDU_DRIVE_GET_CLASS (drive);
+ return klass->create_volume_finish (drive,
+ res,
+ error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/gdu/gdu-drive.h b/src/gdu/gdu-drive.h
index e0d7690..5559fb9 100644
--- a/src/gdu/gdu-drive.h
+++ b/src/gdu/gdu-drive.h
@@ -40,6 +40,21 @@ G_BEGIN_DECLS
typedef struct _GduDriveClass GduDriveClass;
typedef struct _GduDrivePrivate GduDrivePrivate;
+/* TODO: move to gdu-enums.h */
+/**
+ * GduCreateVolumeFlags:
+ * @GDU_CREATE_VOLUME_FLAGS_NONE: No flags are set.
+ * @GDU_CREATE_VOLUME_FLAGS_LINUX_MD: The volume is to be used for Linux MD RAID.
+ * @GDU_CREATE_VOLUME_FLAGS_LINUX_LVM2: The volume is to be used for Linux LVM2.
+ *
+ * Flags used in gdu_drive_create_volume().
+ */
+typedef enum {
+ GDU_CREATE_VOLUME_FLAGS_NONE = 0x00,
+ GDU_CREATE_VOLUME_FLAGS_LINUX_MD = (1<<0),
+ GDU_CREATE_VOLUME_FLAGS_LINUX_LVM2 = (1<<1)
+} GduCreateVolumeFlags;
+
struct _GduDrive
{
GObject parent;
@@ -66,12 +81,22 @@ struct _GduDriveClass
GduDriveDeactivateFunc callback,
gpointer user_data);
- gboolean (*has_unallocated_space) (GduDrive *drive,
- gboolean *out_whole_disk_is_unitialized,
- guint64 *out_largest_segment,
+ gboolean (*can_create_volume) (GduDrive *drive,
+ gboolean *out_is_uninitialized,
+ guint64 *out_largest_contiguous_free_segment,
guint64 *out_total_free,
GduPresentable **out_presentable);
+ void (*create_volume) (GduDrive *drive,
+ guint64 size,
+ const gchar *name,
+ GduCreateVolumeFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+ GduVolume *(*create_volume_finish) (GduDrive *drive,
+ GAsyncResult *res,
+ GError **error);
};
GType gdu_drive_get_type (void);
@@ -88,12 +113,24 @@ void gdu_drive_deactivate (GduDrive *drive,
GduDriveDeactivateFunc callback,
gpointer user_data);
-gboolean gdu_drive_has_unallocated_space (GduDrive *drive,
- gboolean *out_whole_disk_is_unitialized,
- guint64 *out_largest_segment,
+
+gboolean gdu_drive_can_create_volume (GduDrive *drive,
+ gboolean *out_is_uninitialized,
+ guint64 *out_largest_contiguous_free_segment,
guint64 *out_total_free,
GduPresentable **out_presentable);
+void gdu_drive_create_volume (GduDrive *drive,
+ guint64 size,
+ const gchar *name,
+ GduCreateVolumeFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GduVolume *gdu_drive_create_volume_finish (GduDrive *drive,
+ GAsyncResult *res,
+ GError **error);
+
gboolean gdu_drive_count_mbr_partitions (GduDrive *drive,
guint *out_num_primary_partitions,
gboolean *out_has_extended_partition);
diff --git a/src/gdu/gdu-linux-lvm2-volume-group.c b/src/gdu/gdu-linux-lvm2-volume-group.c
index 128e8a9..fe830a0 100644
--- a/src/gdu/gdu-linux-lvm2-volume-group.c
+++ b/src/gdu/gdu-linux-lvm2-volume-group.c
@@ -31,6 +31,7 @@
#include "gdu-linux-lvm2-volume-group.h"
#include "gdu-linux-lvm2-volume.h"
#include "gdu-presentable.h"
+#include "gdu-volume-hole.h"
struct _GduLinuxLvm2VolumeGroupPrivate
{
@@ -59,6 +60,23 @@ static gboolean gdu_linux_lvm2_volume_group_is_activatable (GduDrive *drive);
static gboolean gdu_linux_lvm2_volume_group_can_deactivate (GduDrive *drive);
static gboolean gdu_linux_lvm2_volume_group_can_activate (GduDrive *drive, gboolean *out_degraded);
+static gboolean gdu_linux_lvm2_volume_group_can_create_volume (GduDrive *drive,
+ gboolean *out_is_uninitialized,
+ guint64 *out_largest_contiguous_free_segment,
+ guint64 *out_total_free,
+ GduPresentable **out_presentable);
+
+static void gdu_linux_lvm2_volume_group_create_volume (GduDrive *drive,
+ guint64 size,
+ const gchar *name,
+ GduCreateVolumeFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static GduVolume *gdu_linux_lvm2_volume_group_create_volume_finish (GduDrive *drive,
+ GAsyncResult *res,
+ GError **error);
+
static void on_device_added (GduPool *pool, GduDevice *device, gpointer user_data);
static void on_device_removed (GduPool *pool, GduDevice *device, gpointer user_data);
static void on_device_changed (GduPool *pool, GduDevice *device, gpointer user_data);
@@ -112,6 +130,9 @@ gdu_linux_lvm2_volume_group_class_init (GduLinuxLvm2VolumeGroupClass *klass)
drive_class->is_activatable = gdu_linux_lvm2_volume_group_is_activatable;
drive_class->can_deactivate = gdu_linux_lvm2_volume_group_can_deactivate;
drive_class->can_activate = gdu_linux_lvm2_volume_group_can_activate;
+ drive_class->can_create_volume = gdu_linux_lvm2_volume_group_can_create_volume;
+ drive_class->create_volume = gdu_linux_lvm2_volume_group_create_volume;
+ drive_class->create_volume_finish = gdu_linux_lvm2_volume_group_create_volume_finish;
}
static void
@@ -528,6 +549,157 @@ gdu_linux_lvm2_volume_group_can_activate (GduDrive *drive,
return FALSE;
}
+static gboolean
+gdu_linux_lvm2_volume_group_can_create_volume (GduDrive *drive,
+ gboolean *out_is_uninitialized,
+ guint64 *out_largest_contiguous_free_segment,
+ guint64 *out_total_free,
+ GduPresentable **out_presentable)
+{
+ GList *enclosed_presentables;
+ GList *l;
+ guint64 largest_contiguous_free_segment;
+ guint64 total_free;
+ GduPresentable *pres;
+ gboolean ret;
+ GduPool *pool;
+
+ largest_contiguous_free_segment = 0;
+ total_free = 0;
+ pres = NULL;
+ ret = FALSE;
+
+ pool = gdu_presentable_get_pool (GDU_PRESENTABLE (drive));
+
+ enclosed_presentables = gdu_pool_get_enclosed_presentables (pool, GDU_PRESENTABLE (drive));
+ for (l = enclosed_presentables; l != NULL; l = l->next) {
+ GduPresentable *ep = GDU_PRESENTABLE (l->data);
+
+ if (GDU_IS_VOLUME_HOLE (ep)) {
+ guint64 size;
+
+ size = gdu_presentable_get_size (ep);
+
+ if (size > largest_contiguous_free_segment) {
+ largest_contiguous_free_segment = size;
+ pres = ep;
+ }
+
+ total_free += size;
+
+ }
+ }
+ g_list_foreach (enclosed_presentables, (GFunc) g_object_unref, NULL);
+ g_list_free (enclosed_presentables);
+
+ if (out_largest_contiguous_free_segment != NULL)
+ *out_largest_contiguous_free_segment = largest_contiguous_free_segment;
+
+ if (out_total_free != NULL)
+ *out_total_free = total_free;
+
+ if (out_is_uninitialized != NULL)
+ *out_is_uninitialized = FALSE;
+
+ if (out_presentable != NULL) {
+ *out_presentable = (pres != NULL ? g_object_ref (pres) : NULL);
+ }
+
+ ret = (largest_contiguous_free_segment > 0);
+
+ g_object_unref (pool);
+
+ return ret;
+}
+
+static void
+lvm2_lv_create_op_callback (GduPool *pool,
+ gchar *created_device_object_path,
+ GError *error,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ } else {
+ GduDevice *d;
+ GduPresentable *volume;
+
+ d = gdu_pool_get_by_object_path (pool, created_device_object_path);
+ g_assert (d != NULL);
+
+ volume = gdu_pool_get_volume_by_device (pool, d);
+ g_assert (volume != NULL);
+
+ g_simple_async_result_set_op_res_gpointer (simple, volume, g_object_unref);
+
+ g_object_unref (d);
+ }
+ g_simple_async_result_complete_in_idle (simple);
+}
+
+static void
+gdu_linux_lvm2_volume_group_create_volume (GduDrive *drive,
+ guint64 size,
+ const gchar *name,
+ GduCreateVolumeFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GduLinuxLvm2VolumeGroup *vg = GDU_LINUX_LVM2_VOLUME_GROUP (drive);
+ GSimpleAsyncResult *simple;
+ gchar *volume_name;
+
+ g_return_if_fail (GDU_IS_DRIVE (drive));
+
+ simple = g_simple_async_result_new (G_OBJECT (drive),
+ callback,
+ user_data,
+ gdu_linux_lvm2_volume_group_create_volume);
+
+ /* For now, just use a generic LV name - TODO: include RAID/LVM etc */
+ volume_name = gdu_linux_lvm2_volume_group_get_compute_new_lv_name (vg);
+
+ gdu_pool_op_linux_lvm2_lv_create (vg->priv->pool,
+ vg->priv->uuid,
+ volume_name,
+ size,
+ 0, /* num_stripes */
+ 0, /* stripe_size */
+ 0, /* num_mirrors */
+ "", /* fs_type */
+ "", /* fs_label */
+ "", /* encrypt_passphrase */
+ FALSE, /* fs_take_ownership */
+ lvm2_lv_create_op_callback,
+ simple);
+}
+
+static GduVolume *
+gdu_linux_lvm2_volume_group_create_volume_finish (GduDrive *drive,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GduVolume *ret;
+
+ g_return_val_if_fail (GDU_IS_DRIVE (drive), NULL);
+ g_return_val_if_fail (res != NULL, NULL);
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == gdu_linux_lvm2_volume_group_create_volume);
+
+ ret = NULL;
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ ret = GDU_VOLUME (g_simple_async_result_get_op_res_gpointer (simple));
+
+ out:
+ return ret;
+}
+
/* ---------------------------------------------------------------------------------------------------- */
/**
diff --git a/src/gdu/gdu-linux-md-drive.c b/src/gdu/gdu-linux-md-drive.c
index 0b5ffc0..dbed728 100644
--- a/src/gdu/gdu-linux-md-drive.c
+++ b/src/gdu/gdu-linux-md-drive.c
@@ -597,10 +597,9 @@ get_names_and_desc (GduPresentable *presentable,
gdu_device_get_device_file (drive->priv->device),
gdu_device_linux_md_get_state (drive->priv->device));
} else {
- g_warn_if_fail (drive->priv->device_file != NULL);
-
/* Translators: %s is a device file such as /dev/sda4 */
- ret = g_strdup_printf (_("RAID device %s"), drive->priv->device_file);
+ ret = g_strdup_printf (_("RAID device %s"),
+ drive->priv->device_file != NULL ? drive->priv->device_file : "(unknown)");
}
/* Fallback for level_str */
@@ -687,6 +686,7 @@ gdu_linux_md_drive_get_icon (GduPresentable *presentable)
level = gdu_device_linux_md_get_level (drive->priv->device);
}
+ emblem_name = NULL;
if (g_strcmp0 (level, "linear") == 0) {
emblem_name = "gdu-emblem-raid-linear";
} else if (g_strcmp0 (level, "raid0") == 0) {
@@ -701,8 +701,6 @@ gdu_linux_md_drive_get_icon (GduPresentable *presentable)
emblem_name = "gdu-emblem-raid6";
} else if (g_strcmp0 (level, "raid10") == 0) {
emblem_name = "gdu-emblem-raid10";
- } else {
- g_warning ("Unknown level `%s'", level);
}
return gdu_util_get_emblemed_icon ("gdu-multidisk-drive", emblem_name);
diff --git a/src/gdu/gdu-pool.c b/src/gdu/gdu-pool.c
index 32b5887..5d7ee00 100644
--- a/src/gdu/gdu-pool.c
+++ b/src/gdu/gdu-pool.c
@@ -1303,6 +1303,7 @@ recompute_presentables (GduPool *pool)
vg_uuid,
uuid,
GDU_PRESENTABLE (vg));
+
new_presentables = g_list_prepend (new_presentables, volume);
} else {
diff --git a/src/palimpsest/gdu-section-linux-lvm2-volume-group.c b/src/palimpsest/gdu-section-linux-lvm2-volume-group.c
index 48ac582..e3d2c5c 100644
--- a/src/palimpsest/gdu-section-linux-lvm2-volume-group.c
+++ b/src/palimpsest/gdu-section-linux-lvm2-volume-group.c
@@ -338,11 +338,11 @@ do_add_pv (AddPvData *data)
p = NULL;
d = NULL;
- g_warn_if_fail (gdu_drive_has_unallocated_space (data->drive_to_add_to,
- &whole_disk_is_uninitialized,
- &largest_segment,
- NULL, /* total_free */
- &p));
+ g_warn_if_fail (gdu_drive_can_create_volume (data->drive_to_add_to,
+ &whole_disk_is_uninitialized,
+ &largest_segment,
+ NULL, /* total_free */
+ &p));
g_assert (p != NULL);
g_assert_cmpint (data->size, <=, largest_segment);
diff --git a/src/palimpsest/gdu-section-linux-md-drive.c b/src/palimpsest/gdu-section-linux-md-drive.c
index ec479f9..cbbb010 100644
--- a/src/palimpsest/gdu-section-linux-md-drive.c
+++ b/src/palimpsest/gdu-section-linux-md-drive.c
@@ -726,11 +726,11 @@ do_add_component (AddComponentData *data)
if (linux_md_device == NULL)
goto out;
- g_warn_if_fail (gdu_drive_has_unallocated_space (data->drive_to_add_to,
- &whole_disk_is_uninitialized,
- &largest_segment,
- NULL, /* total_free */
- &p));
+ g_warn_if_fail (gdu_drive_can_create_volume (data->drive_to_add_to,
+ &whole_disk_is_uninitialized,
+ &largest_segment,
+ NULL, /* total_free */
+ &p));
g_assert (p != NULL);
g_assert_cmpint (data->size, <=, largest_segment);
diff --git a/src/palimpsest/gdu-shell.c b/src/palimpsest/gdu-shell.c
index 17d9cbd..b8883e0 100644
--- a/src/palimpsest/gdu-shell.c
+++ b/src/palimpsest/gdu-shell.c
@@ -580,61 +580,35 @@ create_linux_md_data_free (CreateLinuxMdData *data)
static void create_linux_md_do (CreateLinuxMdData *data);
static void
-new_linux_md_create_part_cb (GduDevice *device,
- gchar *created_device_object_path,
- GError *error,
- gpointer user_data)
+md_raid_create_volume_cb (GduDrive *drive,
+ GAsyncResult *res,
+ gpointer user_data)
{
CreateLinuxMdData *data = user_data;
+ GduVolume *volume;
+ GError *error;
- if (error != NULL) {
+ error = NULL;
+ volume = gdu_drive_create_volume_finish (drive,
+ res,
+ &error);
+ if (volume == NULL) {
gdu_shell_raise_error (data->shell,
NULL,
error,
_("Error creating component for RAID array"));
g_error_free (error);
-
- //g_debug ("Error creating component");
} else {
GduDevice *d;
- GduPool *pool;
-
- pool = gdu_device_get_pool (device);
- d = gdu_pool_get_by_object_path (pool, created_device_object_path);
+ d = gdu_presentable_get_device (GDU_PRESENTABLE (volume));
g_ptr_array_add (data->components, d);
-
- //g_debug ("Done creating component");
+ g_object_unref (volume);
/* now that we have a component... carry on... */
create_linux_md_do (data);
-
- g_object_unref (pool);
}
-}
-
-static void
-new_linux_md_create_part_table_cb (GduDevice *device,
- GError *error,
- gpointer user_data)
-{
- CreateLinuxMdData *data = user_data;
-
- if (error != NULL) {
- gdu_shell_raise_error (data->shell,
- NULL,
- error,
- _("Error creating partition table for component for RAID array"));
- g_error_free (error);
- //g_debug ("Error creating partition table");
- } else {
-
- //g_debug ("Done creating partition table");
-
- /* now that we have a partition table... carry on... */
- create_linux_md_do (data);
- }
}
static void
@@ -699,82 +673,16 @@ create_linux_md_do (CreateLinuxMdData *data)
} else {
GduDrive *drive;
guint num_component;
- GduPresentable *p;
- GduDevice *d;
- guint64 largest_segment;
- gboolean whole_disk_is_uninitialized;
num_component = data->components->len;
drive = GDU_DRIVE (data->drives->pdata[num_component]);
- g_warn_if_fail (gdu_drive_has_unallocated_space (drive,
- &whole_disk_is_uninitialized,
- &largest_segment,
- NULL, /* total_free */
- &p));
- g_assert (p != NULL);
-
- d = gdu_presentable_get_device (GDU_PRESENTABLE (drive));
-
- if (GDU_IS_VOLUME_HOLE (p)) {
- guint64 offset;
- guint64 size;
- const gchar *scheme;
- const gchar *type;
- gchar *label;
-
- offset = gdu_presentable_get_offset (p);
- size = data->component_size;
-
- //g_debug ("Creating component %d/%d of size %" G_GUINT64_FORMAT " bytes",
- // num_component + 1,
- // data->drives->len,
- // size);
-
- scheme = gdu_device_partition_table_get_scheme (d);
- type = "";
- label = NULL;
- if (g_strcmp0 (scheme, "mbr") == 0) {
- type = "0xfd";
- } else if (g_strcmp0 (scheme, "gpt") == 0) {
- type = "A19D880F-05FC-4D3B-A006-743F0F84911E";
- /* Limited to 36 UTF-16LE characters according to on-disk format..
- * Since a RAID array name is limited to 32 chars this should fit */
- label = g_strdup_printf ("RAID: %s", data->name);
- } else if (g_strcmp0 (scheme, "apt") == 0) {
- type = "Apple_Unix_SVR2";
- label = g_strdup_printf ("RAID: %s", data->name);
- }
-
- gdu_device_op_partition_create (d,
- offset,
- size,
- type,
- label != NULL ? label : "",
- NULL,
- "",
- "",
- "",
- FALSE,
- new_linux_md_create_part_cb,
- data);
- g_free (label);
-
- } else {
-
- /* otherwise the whole disk must be uninitialized... */
- g_assert (whole_disk_is_uninitialized);
-
- /* so create a partition table... */
- gdu_device_op_partition_table_create (d,
- "mbr",
- new_linux_md_create_part_table_cb,
- data);
- }
-
- g_object_unref (d);
- g_object_unref (p);
-
+ gdu_drive_create_volume (drive,
+ data->component_size,
+ data->name,
+ GDU_CREATE_VOLUME_FLAGS_LINUX_MD,
+ (GAsyncReadyCallback) md_raid_create_volume_cb,
+ data);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]