Commit 121e7e1c authored by David Zeuthen's avatar David Zeuthen

First usable version of the Create RAID Array dialog

Still missing

 o We only support creating RAID0, RAID1, RAID5 and RAID6 arrays. Notes about
   missing levels

   - Linear: People should be using LVM instead. We will support that at some
             point.

   - RAID4: We could add this but people should be using RAID5 instead. Having
            both would be confusing.

   - RAID10: It is probably more logical to avoid this. People can obtain
             the same effect by create a RAID1 of RAID0s.

   - multipath: ... sigh

   - faulty: This is only for debugging.

   - container: Need to research if Fakeraid etc. using md needs to be treated
     separately. It probably does.

 o Progress dialog. This will be added in a subsequent commit. The idea is to
   refactor src/format-tool/gdu-format-progress-dialog.c into a generic
   GduProgressDialog class.
parent ff5759c2
This diff is collapsed.
......@@ -50,11 +50,15 @@ struct GduCreateLinuxMdDialogClass
GtkDialogClass parent_class;
};
GType gdu_create_linux_md_dialog_get_type (void) G_GNUC_CONST;
GtkWidget* gdu_create_linux_md_dialog_new (GtkWindow *parent,
GduPool *pool);
gchar *gdu_create_linux_md_dialog_get_level (GduCreateLinuxMdDialog *dialog);
gchar *gdu_create_linux_md_dialog_get_name (GduCreateLinuxMdDialog *dialog);
GType gdu_create_linux_md_dialog_get_type (void) G_GNUC_CONST;
GtkWidget* gdu_create_linux_md_dialog_new (GtkWindow *parent,
GduPool *pool);
gchar *gdu_create_linux_md_dialog_get_level (GduCreateLinuxMdDialog *dialog);
gchar *gdu_create_linux_md_dialog_get_name (GduCreateLinuxMdDialog *dialog);
guint64 gdu_create_linux_md_dialog_get_size (GduCreateLinuxMdDialog *dialog);
guint64 gdu_create_linux_md_dialog_get_component_size (GduCreateLinuxMdDialog *dialog);
guint64 gdu_create_linux_md_dialog_get_stripe_size (GduCreateLinuxMdDialog *dialog);
GPtrArray *gdu_create_linux_md_dialog_get_drives (GduCreateLinuxMdDialog *dialog);
G_END_DECLS
......
......@@ -30,25 +30,27 @@
/**
* GduPoolTreeModelColumn:
* @GDU_POOL_TREE_MODEL_COLUMN_ICON: The icon for the presentable.
* @GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME: Name for the presentable derived from Vital Product Data,
* e.g. "ATA INTEL SSDSA2MH080G1GC".
* @GDU_POOL_TREE_MODEL_COLUMN_ICON: The #GIcon for the presentable.
* @GDU_POOL_TREE_MODEL_COLUMN_NAME: Human readable name of the presentable, e.g. "80 GB Solid-state Disk" or
* "Fedora (Rawhide)".
* @GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME: Name for the presentable derived from Vital Product Data,
* e.g. "ATA INTEL SSDSA2MH080G1GC".
* @GDU_POOL_TREE_MODEL_COLUMN_DESCRIPTION: Human readable description of the presentable, e.g. "MBR Partition Table"
* or "32GB Linux ext3".
* @GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE: The #GduPresentable object.
* @GDU_POOL_TREE_MODEL_COLUMN_TOGGLED: Whether the item can be toggled.
* @GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED: Whether the item is toggled.
* @GDU_POOL_TREE_MODEL_COLUMN_VISIBLE: Whether the item is visible.
* @GDU_POOL_TREE_MODEL_COLUMN_TOGGLED: Whether the item is toggled.
* @GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED: Whether the item can be toggled.
*
* Columns used in #GduPoolTreeModel.
*/
typedef enum {
GDU_POOL_TREE_MODEL_COLUMN_ICON,
GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME,
GDU_POOL_TREE_MODEL_COLUMN_NAME,
GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME,
GDU_POOL_TREE_MODEL_COLUMN_DESCRIPTION,
GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE,
GDU_POOL_TREE_MODEL_COLUMN_VISIBLE,
GDU_POOL_TREE_MODEL_COLUMN_TOGGLED,
GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED,
} GduPoolTreeModelColumn;
......@@ -58,4 +60,18 @@ typedef enum {
GDU_POOL_TREE_VIEW_FLAGS_SHOW_TOGGLE = (1<<0),
} GduPoolTreeViewFlags;
/**
* GduPoolTreeModelFlags:
* @GDU_POOL_TREE_MODEL_FLAGS_NONE: No flags set.
* @GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES: Don't include presentables representing volumes or holes.
* @GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES: Don't include drives that cannot be allocated to e.g. a RAID array.
*
* Flags used when creating a #GduPoolTreeModel.
*/
typedef enum {
GDU_POOL_TREE_MODEL_FLAGS_NONE = 0,
GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES = (1<<0),
GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES = (1<<2),
} GduPoolTreeModelFlags;
#endif /* GDU_GTK_ENUMS_H */
......@@ -30,6 +30,7 @@
struct GduPoolTreeModelPrivate
{
GduPool *pool;
GduPoolTreeModelFlags flags;
};
G_DEFINE_TYPE (GduPoolTreeModel, gdu_pool_tree_model, GTK_TYPE_TREE_STORE)
......@@ -38,6 +39,7 @@ enum
{
PROP_0,
PROP_POOL,
PROP_FLAGS,
};
/* ---------------------------------------------------------------------------------------------------- */
......@@ -70,6 +72,10 @@ gdu_pool_tree_model_set_property (GObject *object,
model->priv->pool = g_value_dup_object (value);
break;
case PROP_FLAGS:
model->priv->flags = g_value_get_flags (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -89,6 +95,10 @@ gdu_pool_tree_model_get_property (GObject *object,
g_value_set_object (value, model->priv->pool);
break;
case PROP_FLAGS:
g_value_set_flags (value, model->priv->flags);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -142,17 +152,18 @@ static void
gdu_pool_tree_model_constructed (GObject *object)
{
GduPoolTreeModel *model = GDU_POOL_TREE_MODEL (object);
GType column_types[7];
GType column_types[8];
GList *presentables;
GList *l;
column_types[0] = GDK_TYPE_PIXBUF;
column_types[0] = G_TYPE_ICON;
column_types[1] = G_TYPE_STRING;
column_types[2] = G_TYPE_STRING;
column_types[3] = G_TYPE_STRING;
column_types[4] = GDU_TYPE_PRESENTABLE;
column_types[5] = G_TYPE_BOOLEAN;
column_types[6] = G_TYPE_BOOLEAN;
column_types[7] = G_TYPE_BOOLEAN;
gtk_tree_store_set_column_types (GTK_TREE_STORE (object),
G_N_ELEMENTS (column_types),
......@@ -222,6 +233,22 @@ gdu_pool_tree_model_class_init (GduPoolTreeModelClass *klass)
G_PARAM_WRITABLE |
G_PARAM_READABLE |
G_PARAM_CONSTRUCT_ONLY));
/**
* GduPoolTreeModel:flags:
*
* The flags for the model.
*/
g_object_class_install_property (gobject_class,
PROP_FLAGS,
g_param_spec_flags ("flags",
NULL,
NULL,
GDU_TYPE_POOL_TREE_MODEL_FLAGS,
GDU_POOL_TREE_MODEL_FLAGS_NONE,
G_PARAM_WRITABLE |
G_PARAM_READABLE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
......@@ -231,10 +258,12 @@ gdu_pool_tree_model_init (GduPoolTreeModel *model)
}
GduPoolTreeModel *
gdu_pool_tree_model_new (GduPool *pool)
gdu_pool_tree_model_new (GduPool *pool,
GduPoolTreeModelFlags flags)
{
return GDU_POOL_TREE_MODEL (g_object_new (GDU_TYPE_POOL_TREE_MODEL,
"pool", pool,
"flags", flags,
NULL));
}
......@@ -305,7 +334,7 @@ set_data_for_presentable (GduPoolTreeModel *model,
GduPresentable *presentable)
{
GduDevice *device;
GdkPixbuf *pixbuf;
GIcon *icon;
gchar *vpd_name;
gchar *name;
gchar *desc;
......@@ -314,27 +343,24 @@ set_data_for_presentable (GduPoolTreeModel *model,
name = gdu_presentable_get_name (presentable);
desc = gdu_presentable_get_description (presentable);
vpd_name = gdu_presentable_get_vpd_name (presentable);
// TODO:
//vpd_name = gdu_presentable_get_vpd_name (presentable);
vpd_name = g_strdup ("foo");
pixbuf = gdu_util_get_pixbuf_for_presentable (presentable, GTK_ICON_SIZE_SMALL_TOOLBAR);
icon = gdu_presentable_get_icon (presentable);
/* TODO: insert NAME */
gtk_tree_store_set (GTK_TREE_STORE (model),
iter,
GDU_POOL_TREE_MODEL_COLUMN_ICON, pixbuf,
GDU_POOL_TREE_MODEL_COLUMN_ICON, icon,
GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME, vpd_name,
GDU_POOL_TREE_MODEL_COLUMN_NAME, name,
GDU_POOL_TREE_MODEL_COLUMN_DESCRIPTION, desc,
GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, presentable,
GDU_POOL_TREE_MODEL_COLUMN_VISIBLE, TRUE,
GDU_POOL_TREE_MODEL_COLUMN_TOGGLED, FALSE,
GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED, FALSE,
-1);
if (pixbuf != NULL)
g_object_unref (pixbuf);
g_object_unref (icon);
g_free (vpd_name);
g_free (name);
g_free (desc);
......@@ -342,6 +368,32 @@ set_data_for_presentable (GduPoolTreeModel *model,
g_object_unref (device);
}
static gboolean
should_include_presentable (GduPoolTreeModel *model,
GduPresentable *presentable)
{
gboolean ret;
ret = FALSE;
/* see if it should be ignored because it is a volume */
if ((model->priv->flags & GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES) &&
(GDU_IS_VOLUME (presentable) || GDU_IS_VOLUME_HOLE (presentable)))
goto out;
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)))
goto out;
}
ret = TRUE;
out:
return ret;
}
static void
add_presentable (GduPoolTreeModel *model,
GduPresentable *presentable,
......@@ -356,6 +408,9 @@ add_presentable (GduPoolTreeModel *model,
if (gdu_pool_tree_model_get_iter_for_presentable (model, presentable, NULL))
goto out;
if (!should_include_presentable (model, presentable))
goto out;
/* set up parent relationship */
parent_iter = NULL;
enclosing_presentable = gdu_presentable_get_enclosing_presentable (presentable);
......@@ -421,6 +476,9 @@ on_presentable_changed (GduPool *pool,
GduPoolTreeModel *model = GDU_POOL_TREE_MODEL (user_data);
GtkTreeIter iter;
/* will do NOP if presentable has already been added */
add_presentable (model, presentable, NULL);
/* update name and icon */
if (gdu_pool_tree_model_get_iter_for_presentable (model, presentable, &iter)) {
......
......@@ -53,10 +53,11 @@ struct GduPoolTreeModelClass
};
GType gdu_pool_tree_model_get_type (void);
GduPoolTreeModel *gdu_pool_tree_model_new (GduPool *pool);
gboolean gdu_pool_tree_model_get_iter_for_presentable (GduPoolTreeModel *model,
GduPresentable *presentable,
GtkTreeIter *out_iter);
GType gdu_pool_tree_model_get_type (void) G_GNUC_CONST;
GduPoolTreeModel *gdu_pool_tree_model_new (GduPool *pool,
GduPoolTreeModelFlags flags);
gboolean gdu_pool_tree_model_get_iter_for_presentable (GduPoolTreeModel *model,
GduPresentable *presentable,
GtkTreeIter *out_iter);
#endif /* GDU_POOL_TREE_MODEL_H */
......@@ -147,7 +147,9 @@ format_markup (GtkCellLayout *cell_layout,
GduPoolTreeView *view = GDU_POOL_TREE_VIEW (user_data);
GtkTreeSelection *tree_selection;
gchar *name;
gchar *vpd_name;
gchar *desc;
GduPresentable *p;
gchar *markup;
GtkStyle *style;
GdkColor desc_gdk_color = {0};
......@@ -158,7 +160,9 @@ format_markup (GtkCellLayout *cell_layout,
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,
GDU_POOL_TREE_MODEL_COLUMN_DESCRIPTION, &desc,
-1);
......@@ -185,11 +189,23 @@ format_markup (GtkCellLayout *cell_layout,
(desc_gdk_color.green >> 8),
(desc_gdk_color.blue >> 8));
markup = g_strdup_printf ("<b>%s</b>\n"
"<span fgcolor=\"%s\"><small>%s</small></span>",
name,
desc_color,
desc);
/* Only include VPD name for drives */
if (GDU_IS_DRIVE (p)) {
markup = g_strdup_printf ("<b>%s</b>\n"
"<span fgcolor=\"%s\"><small>%s\n%s</small></span>",
name,
desc_color,
vpd_name,
desc);
} else {
markup = g_strdup_printf ("<small>"
"<b>%s</b>\n"
"<span fgcolor=\"%s\">%s</span>"
"</small>",
name,
desc_color,
desc);
}
g_object_set (renderer,
"markup", markup,
......@@ -197,8 +213,65 @@ format_markup (GtkCellLayout *cell_layout,
g_free (name);
g_free (desc);
g_free (vpd_name);
g_free (markup);
g_free (desc_color);
g_object_unref (p);
}
static void
pixbuf_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *renderer,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer user_data)
{
GduPoolTreeView *view = GDU_POOL_TREE_VIEW (user_data);
GduPresentable *p;
GIcon *icon;
gtk_tree_model_get (tree_model,
iter,
GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
GDU_POOL_TREE_MODEL_COLUMN_ICON, &icon,
-1);
#if 0
gint width, height;
GdkPixbuf *pixbuf;
gtk_tree_view_column_cell_get_size (GTK_TREE_VIEW_COLUMN (cell_layout),
NULL,
NULL,
NULL,
&width,
&height);
//g_debug ("w=%d h=%d", width, height);
pixbuf = gdu_util_get_pixbuf_for_presentable_at_pixel_size (p,
height * 5 / 6);
g_object_set (renderer,
"pixbuf", pixbuf,
"width", 48,
"height", 0,
NULL);
g_object_unref (pixbuf);
#else
GtkIconSize size;
size = GTK_ICON_SIZE_SMALL_TOOLBAR;
if (GDU_IS_VOLUME (p) || GDU_IS_VOLUME_HOLE (p)) {
size = GTK_ICON_SIZE_MENU;
}
g_object_set (renderer,
"gicon", icon,
"stock-size", size,
NULL);
#endif
g_object_unref (p);
g_object_unref (icon);
}
static void
......@@ -219,7 +292,6 @@ gdu_pool_tree_view_constructed (GObject *object)
FALSE);
gtk_tree_view_column_set_attributes (column,
renderer,
"visible", GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED,
"active", GDU_POOL_TREE_MODEL_COLUMN_TOGGLED,
NULL);
g_signal_connect (renderer,
......@@ -230,10 +302,11 @@ gdu_pool_tree_view_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,
"pixbuf", GDU_POOL_TREE_MODEL_COLUMN_ICON,
NULL);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
renderer,
pixbuf_data_func,
view,
NULL);
if (view->priv->flags & GDU_POOL_TREE_VIEW_FLAGS_SHOW_TOGGLE) {
gtk_tree_view_column_add_attribute (column,
renderer,
......@@ -262,6 +335,7 @@ gdu_pool_tree_view_constructed (GObject *object)
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (view), FALSE);
gtk_tree_view_set_enable_tree_lines (GTK_TREE_VIEW (view), TRUE);
gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (view), 16);
gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
......
......@@ -55,6 +55,8 @@ guint signals[LAST_SIGNAL] = {0,};
G_DEFINE_TYPE (GduSizeWidget, gdu_size_widget, GTK_TYPE_HBOX)
static void update_stepping (GduSizeWidget *widget);
static void
gdu_size_widget_finalize (GObject *object)
{
......@@ -216,6 +218,8 @@ gdu_size_widget_constructed (GObject *object)
G_CALLBACK (on_query_tooltip),
widget);
update_stepping (widget);
if (G_OBJECT_CLASS (gdu_size_widget_parent_class)->constructed != NULL)
G_OBJECT_CLASS (gdu_size_widget_parent_class)->constructed (object);
}
......
......@@ -70,10 +70,18 @@ do_update (GduTimeLabel *time_label)
s = g_strdup_printf (_("Less than a minute ago"));
next_update = 60 - age;
} else if (age < 60 * 60) {
s = g_strdup_printf (ngettext ("%d minute ago", "%d minutes ago", age / 60), age / 60);
s = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
"%d minute ago",
"%d minutes ago",
age / 60),
age / 60);
next_update = 60*(age/60 + 1) - age;
} else {
s = g_strdup_printf (ngettext ("%d hour ago", "%d hours ago", age / 60 / 60), age / 60 / 60);
s = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
"%d hour ago",
"%d hours ago",
age / 60 / 60),
age / 60 / 60);
next_update = 60*60*(age/(60*60) + 1) - age;
}
gtk_label_set_text (GTK_LABEL (time_label), s);
......
......@@ -153,6 +153,11 @@ typedef void (*GduPoolLinuxMdStartCompletedFunc) (GduPool *pool,
GError *error,
gpointer user_data);
typedef void (*GduPoolLinuxMdCreateCompletedFunc) (GduPool *pool,
char *array_object_path,
GError *error,
gpointer user_data);
/* ---------------------------------------------------------------------------------------------------- */
/* GduDrive */
......
......@@ -119,6 +119,7 @@ typedef struct
gboolean drive_is_media_ejectable;
gboolean drive_can_detach;
gboolean drive_can_spindown;
gboolean drive_is_rotational;
gboolean optical_disc_is_blank;
gboolean optical_disc_is_appendable;
......@@ -318,6 +319,8 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props)
props->drive_can_detach = g_value_get_boolean (value);
else if (strcmp (key, "drive-can-spindown") == 0)
props->drive_can_spindown = g_value_get_boolean (value);
else if (strcmp (key, "drive-is-rotational") == 0)
props->drive_is_rotational = g_value_get_boolean (value);
else if (strcmp (key, "optical-disc-is-blank") == 0)
props->optical_disc_is_blank = g_value_get_boolean (value);
......@@ -1115,6 +1118,12 @@ gdu_device_drive_get_can_spindown (GduDevice *device)
return device->priv->props->drive_can_spindown;
}
gboolean
gdu_device_drive_get_is_rotational (GduDevice *device)
{
return device->priv->props->drive_is_rotational;
}
gboolean
gdu_device_optical_disc_get_is_blank (GduDevice *device)
{
......
......@@ -139,6 +139,7 @@ gboolean gdu_device_drive_get_is_media_ejectable (GduDevice *device);
gboolean gdu_device_drive_get_requires_eject (GduDevice *device);
gboolean gdu_device_drive_get_can_detach (GduDevice *device);
gboolean gdu_device_drive_get_can_spindown (GduDevice *device);
gboolean gdu_device_drive_get_is_rotational (GduDevice *device);
gboolean gdu_device_optical_disc_get_is_blank (GduDevice *device);
gboolean gdu_device_optical_disc_get_is_appendable (GduDevice *device);
......
......@@ -20,6 +20,7 @@
*/
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <glib/gi18n.h>
#include <dbus/dbus-glib.h>
......@@ -31,6 +32,8 @@
#include "gdu-presentable.h"
#include "gdu-device.h"
#include "gdu-error.h"
#include "gdu-volume.h"
#include "gdu-volume-hole.h"
/**
* SECTION:gdu-drive
......@@ -63,6 +66,11 @@ 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,
GduPresentable **out_presentable);
static void
gdu_drive_finalize (GduDrive *drive)
{
......@@ -92,6 +100,8 @@ gdu_drive_class_init (GduDriveClass *klass)
obj_class->finalize = (GObjectFinalizeFunc) gdu_drive_finalize;
klass->has_unallocated_space = gdu_drive_has_unallocated_space_real;
g_type_class_add_private (klass, sizeof (GduDrivePrivate));
}
......@@ -183,6 +193,178 @@ gdu_drive_deactivate (GduDrive *drive,
}
}
/**
* gdu_drive_has_unallocated_space:
* @drive: A #GduDrive.
* @out_whole_disk_is_unitialized: Return location for whether @drive is uninitialized or %NULL.
* @out_largest_segment: Return location biggest contigious free block of @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.
*
* 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.
*
* 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
* MBR partitioned disk), this method returns %FALSE but
* @out_largest_segment will be set to a non-zero value.
*
* Additionally, @out_presentable will be set to either a
* #GduVolumeHole (if the disk is partitioned and has free space) or
* the #GduDrive (if the disk is uninitialized).
*
* 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,
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_presentable);
}
static gboolean
gdu_drive_has_unallocated_space_real (GduDrive *drive,
gboolean *out_whole_disk_is_unitialized,
guint64 *out_largest_segment,
GduPresentable **out_presentable)
{
GduDevice *device;
GduPool *pool;
guint64 largest_segment;
gboolean whole_disk_uninitialized;
GList *enclosed_presentables;
GList *l;
gboolean has_extended_partition;
gboolean ret;
guint64 size;
GduPresentable *pres;
largest_segment = 0;
whole_disk_uninitialized = FALSE;
ret = FALSE;
device = NULL;
pool = NULL;
pres = NULL;
device = gdu_presentable_get_device (GDU_PRESENTABLE (drive));
if (device != NULL && gdu_device_is_read_only (device))
goto out;
if (gdu_device_is_removable (device) && !gdu_device_is_media_available (device))
goto out;
/* now figure out @whole_disk_is_uninitialized... this is to be set to %TRUE exactly
* when we _think_ the disk has never been used - we define this to happen when
*
* 1. The disk has no partition table; and
*
* 2. the whole-disk device is unrecognized
*/
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);
ret = TRUE;
pres = GDU_PRESENTABLE (drive);
goto out;
}
pool = gdu_presentable_get_pool (GDU_PRESENTABLE (drive));
has_extended_partition = FALSE;
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)) {
size = gdu_presentable_get_size (ep);
if (size > largest_segment) {
largest_segment = size;
pres = ep;
}
} else if (GDU_IS_VOLUME (ep)) {
gint type;
GduDevice *ep_device;
ep_device = gdu_presentable_get_device (ep);
type = strtol (gdu_device_partition_get_type (ep_device), NULL, 0);
if (type == 0x05 || type == 0x0f || type == 0x85) {
GList *logical_partitions;
GList *ll;
has_extended_partition = TRUE;
/* This is MS-DOS extended partition, count volume holes inside */
logical_partitions = gdu_pool_get_enclosed_presentables (pool, ep);
for (ll = logical_partitions; ll != NULL; ll = ll->next) {
GduPresentable *lep = GDU_PRESENTABLE (ll->data);
if (GDU_IS_VOLUME_HOLE (lep)) {
size = gdu_presentable_get_size (lep);
if (size > largest_segment) {
largest_segment = size;
pres = lep;
}
}
}
g_list_foreach (logical_partitions, (GFunc) g_object_unref, NULL);
g_list_free (logical_partitions);
}
g_object_unref (ep_device);
}
}
g_list_foreach (enclosed_presentables, (GFunc) g_object_unref, NULL);
g_list_free (enclosed_presentables);
ret = (largest_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
*/
if (g_strcmp0 (gdu_device_partition_table_get_scheme (device), "mbr") == 0 &&
gdu_device_partition_table_get_count (device) == 4 &&
!has_extended_partition) {
ret = FALSE;
}
out:
if (device != NULL)
g_object_unref (device);
if (pool != NULL)
g_object_unref (pool);
if (out_largest_segment != NULL)
*out_largest_segment = largest_segment;
if (out_whole_disk_is_unitialized != NULL)
*out_whole_disk_is_unitialized = whole_disk_uninitialized;
if (out_presentable != NULL) {
*out_presentable = (pres != NULL ? g_object_ref (pres) : NULL);
}
return ret;
}
static void
gdu_drive_init (GduDrive *drive)
......@@ -272,7 +454,7 @@ gdu_drive_get_name (GduPresentable *presentable)
is_removable = gdu_device_is_removable (drive->priv->device);
media_compat = (const gchar* const *) gdu_device_drive_get_media_compatibility (drive->priv->device);
has_media = gdu_device_is_media_available (drive->priv->device);
is_rotational = TRUE; /* TODO: add support in DKD for this */