[gnome-disk-utility] First cut add creating LVM2 Logical Volumes



commit 019aab391ec9918ff649f85df569d38b8fd8e291
Author: David Zeuthen <davidz redhat com>
Date:   Tue Jan 12 16:01:43 2010 -0500

    First cut add creating LVM2 Logical Volumes
    
    Still need support for setting up striping and mirroring.

 src/gdu-gtk/Makefile.am                           |    2 +
 src/gdu-gtk/gdu-create-linux-lvm2-volume-dialog.c |  230 +++++++++++++++++++++
 src/gdu-gtk/gdu-create-linux-lvm2-volume-dialog.h |   65 ++++++
 src/gdu-gtk/gdu-gtk-types.h                       |   59 +++---
 src/gdu/gdu-callbacks.h                           |    5 +
 src/gdu/gdu-linux-lvm2-volume-group.c             |   69 ++++++
 src/gdu/gdu-linux-lvm2-volume-group.h             |    2 +
 src/gdu/gdu-pool.c                                |   82 +++++++-
 src/gdu/gdu-pool.h                                |   14 ++
 src/palimpsest/gdu-section-volumes.c              |  180 +++++++++++++++--
 10 files changed, 662 insertions(+), 46 deletions(-)
---
diff --git a/src/gdu-gtk/Makefile.am b/src/gdu-gtk/Makefile.am
index 2002b02..4cb665b 100644
--- a/src/gdu-gtk/Makefile.am
+++ b/src/gdu-gtk/Makefile.am
@@ -49,6 +49,7 @@ libgdu_gtkinclude_HEADERS =              				\
 	gdu-format-dialog.h						\
 	gdu-partition-dialog.h						\
 	gdu-create-partition-dialog.h					\
+	gdu-create-linux-lvm2-volume-dialog.h				\
 	gdu-edit-name-dialog.h						\
 	gdu-disk-selection-widget.h					\
 	gdu-add-component-linux-md-dialog.h				\
@@ -81,6 +82,7 @@ libgdu_gtk_la_SOURCES =                 	               				\
 	gdu-format-dialog.h			gdu-format-dialog.c			\
 	gdu-partition-dialog.h			gdu-partition-dialog.c			\
 	gdu-create-partition-dialog.h		gdu-create-partition-dialog.c		\
+	gdu-create-linux-lvm2-volume-dialog.h	gdu-create-linux-lvm2-volume-dialog.c	\
 	gdu-edit-name-dialog.h			gdu-edit-name-dialog.c			\
 	gdu-disk-selection-widget.h		gdu-disk-selection-widget.c		\
 	gdu-add-component-linux-md-dialog.h	gdu-add-component-linux-md-dialog.c	\
diff --git a/src/gdu-gtk/gdu-create-linux-lvm2-volume-dialog.c b/src/gdu-gtk/gdu-create-linux-lvm2-volume-dialog.c
new file mode 100644
index 0000000..3a197db
--- /dev/null
+++ b/src/gdu-gtk/gdu-create-linux-lvm2-volume-dialog.c
@@ -0,0 +1,230 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *          David Zeuthen <davidz redhat com>
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include <gdu/gdu.h>
+#include <gdu-gtk/gdu-gtk.h>
+
+#include "gdu-create-linux-lvm2-volume-dialog.h"
+
+struct GduCreateLinuxLvm2VolumeDialogPrivate
+{
+        guint64 max_size;
+        GtkWidget *size_widget;
+        GduPresentable *drive;
+};
+
+enum
+{
+        PROP_0,
+        PROP_SIZE,
+        PROP_MAX_SIZE,
+        PROP_DRIVE
+};
+
+static void gdu_create_linux_lvm2_volume_dialog_constructed (GObject *object);
+
+G_DEFINE_TYPE (GduCreateLinuxLvm2VolumeDialog, gdu_create_linux_lvm2_volume_dialog, GDU_TYPE_FORMAT_DIALOG)
+
+static void
+gdu_create_linux_lvm2_volume_dialog_finalize (GObject *object)
+{
+        //GduCreateLinuxLvm2VolumeDialog *dialog = GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG (object);
+
+        if (G_OBJECT_CLASS (gdu_create_linux_lvm2_volume_dialog_parent_class)->finalize != NULL)
+                G_OBJECT_CLASS (gdu_create_linux_lvm2_volume_dialog_parent_class)->finalize (object);
+}
+
+static void
+gdu_create_linux_lvm2_volume_dialog_get_property (GObject    *object,
+                                          guint       property_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+        GduCreateLinuxLvm2VolumeDialog *dialog = GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG (object);
+
+        switch (property_id) {
+        case PROP_SIZE:
+                g_value_set_uint64 (value, gdu_create_linux_lvm2_volume_dialog_get_size (dialog));
+                break;
+
+        case PROP_MAX_SIZE:
+                g_value_set_uint64 (value, dialog->priv->max_size);
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_create_linux_lvm2_volume_dialog_set_property (GObject      *object,
+                                                  guint         property_id,
+                                                  const GValue *value,
+                                                  GParamSpec   *pspec)
+{
+        GduCreateLinuxLvm2VolumeDialog *dialog = GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG (object);
+
+        switch (property_id) {
+        case PROP_MAX_SIZE:
+                dialog->priv->max_size = g_value_get_uint64 (value);
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_create_linux_lvm2_volume_dialog_class_init (GduCreateLinuxLvm2VolumeDialogClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        g_type_class_add_private (klass, sizeof (GduCreateLinuxLvm2VolumeDialogPrivate));
+
+        object_class->get_property = gdu_create_linux_lvm2_volume_dialog_get_property;
+        object_class->set_property = gdu_create_linux_lvm2_volume_dialog_set_property;
+        object_class->constructed  = gdu_create_linux_lvm2_volume_dialog_constructed;
+        object_class->finalize     = gdu_create_linux_lvm2_volume_dialog_finalize;
+
+        g_object_class_install_property (object_class,
+                                         PROP_MAX_SIZE,
+                                         g_param_spec_uint64 ("max-size",
+                                                              _("Maximum Logical Volume Size"),
+                                                              _("The maximum possible logical volume size"),
+                                                              0,
+                                                              G_MAXUINT64,
+                                                              0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_SIZE,
+                                         g_param_spec_uint64 ("size",
+                                                              _("Logical Volume Size"),
+                                                              _("The requested Logical Volume size"),
+                                                              0,
+                                                              G_MAXUINT64,
+                                                              0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+}
+
+static void
+gdu_create_linux_lvm2_volume_dialog_init (GduCreateLinuxLvm2VolumeDialog *dialog)
+{
+        dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
+                                                    GDU_TYPE_CREATE_LINUX_LVM2_VOLUME_DIALOG,
+                                                    GduCreateLinuxLvm2VolumeDialogPrivate);
+}
+
+GtkWidget *
+gdu_create_linux_lvm2_volume_dialog_new (GtkWindow            *parent,
+                                         GduPresentable       *presentable,
+                                         guint64               max_size,
+                                         GduFormatDialogFlags  flags)
+{
+        return GTK_WIDGET (g_object_new (GDU_TYPE_CREATE_LINUX_LVM2_VOLUME_DIALOG,
+                                         "transient-for", parent,
+                                         "presentable", presentable,
+                                         "max-size", max_size,
+                                         "affirmative-button-mnemonic", _("C_reate"),
+                                         "flags", flags,
+                                         NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+guint64
+gdu_create_linux_lvm2_volume_dialog_get_size (GduCreateLinuxLvm2VolumeDialog *dialog)
+{
+        g_return_val_if_fail (GDU_IS_CREATE_LINUX_LVM2_VOLUME_DIALOG (dialog), 0);
+        return gdu_size_widget_get_size (GDU_SIZE_WIDGET (dialog->priv->size_widget));
+}
+
+guint64
+gdu_create_linux_lvm2_volume_dialog_get_max_size (GduCreateLinuxLvm2VolumeDialog *dialog)
+{
+        g_return_val_if_fail (GDU_IS_CREATE_LINUX_LVM2_VOLUME_DIALOG (dialog), 0);
+        return dialog->priv->max_size;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_create_linux_lvm2_volume_dialog_constructed (GObject *object)
+{
+        GduCreateLinuxLvm2VolumeDialog *dialog = GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG (object);
+        gchar *s;
+        gchar *s2;
+        GtkWidget *table;
+        GtkWidget *label;
+        GtkWidget *size_widget;
+        guint row;
+
+        table = gdu_format_dialog_get_table (GDU_FORMAT_DIALOG (dialog));
+        g_object_get (table,
+                      "n-rows", &row,
+                      NULL);
+
+        /*  add Logical Volume size widget before other widgets in the GduFormatDialog  */
+        label = gtk_label_new (NULL);
+        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Size:"));
+        gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        size_widget = gdu_size_widget_new (0, 0, dialog->priv->max_size);
+        gdu_size_widget_set_size (GDU_SIZE_WIDGET (size_widget), dialog->priv->max_size);
+        gtk_table_attach (GTK_TABLE (table), size_widget, 1, 2, row, row + 1,
+                          GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        gtk_label_set_mnemonic_widget (GTK_LABEL (label), size_widget);
+        dialog->priv->size_widget = size_widget;
+        row++;
+
+        /* run constructed() for parent class (GduFormatDialog) */
+        if (G_OBJECT_CLASS (gdu_create_linux_lvm2_volume_dialog_parent_class)->constructed != NULL)
+                G_OBJECT_CLASS (gdu_create_linux_lvm2_volume_dialog_parent_class)->constructed (object);
+
+        /* adjust window title */
+        s2 = gdu_presentable_get_vpd_name (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+
+        /* Translators: The %s is the name of the volume group */
+        s = g_strdup_printf (_("Create Logical Volume on %s"), s2);
+        gtk_window_set_title (GTK_WINDOW (dialog), s);
+        g_free (s);
+
+
+        g_free (s2);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/gdu-gtk/gdu-create-linux-lvm2-volume-dialog.h b/src/gdu-gtk/gdu-create-linux-lvm2-volume-dialog.h
new file mode 100644
index 0000000..f69ae8c
--- /dev/null
+++ b/src/gdu-gtk/gdu-create-linux-lvm2-volume-dialog.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: David Zeuthen <davidz redhat com>
+ *
+ */
+
+#ifndef __GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG_H
+#define __GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG_H
+
+#include <gtk/gtk.h>
+#include <gdu-gtk/gdu-gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_CREATE_LINUX_LVM2_VOLUME_DIALOG            gdu_create_linux_lvm2_volume_dialog_get_type()
+#define GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDU_TYPE_CREATE_LINUX_LVM2_VOLUME_DIALOG, GduCreateLinuxLvm2VolumeDialog))
+#define GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDU_TYPE_CREATE_LINUX_LVM2_VOLUME_DIALOG, GduCreateLinuxLvm2VolumeDialogClass))
+#define GDU_IS_CREATE_LINUX_LVM2_VOLUME_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDU_TYPE_CREATE_LINUX_LVM2_VOLUME_DIALOG))
+#define GDU_IS_CREATE_LINUX_LVM2_VOLUME_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDU_TYPE_CREATE_LINUX_LVM2_VOLUME_DIALOG))
+#define GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDU_TYPE_CREATE_LINUX_LVM2_VOLUME_DIALOG, GduCreateLinuxLvm2VolumeDialogClass))
+
+typedef struct GduCreateLinuxLvm2VolumeDialogClass   GduCreateLinuxLvm2VolumeDialogClass;
+typedef struct GduCreateLinuxLvm2VolumeDialogPrivate GduCreateLinuxLvm2VolumeDialogPrivate;
+
+struct GduCreateLinuxLvm2VolumeDialog
+{
+        GduFormatDialog parent;
+
+        /*< private >*/
+        GduCreateLinuxLvm2VolumeDialogPrivate *priv;
+};
+
+struct GduCreateLinuxLvm2VolumeDialogClass
+{
+        GduFormatDialogClass parent_class;
+};
+
+GType       gdu_create_linux_lvm2_volume_dialog_get_type       (void) G_GNUC_CONST;
+GtkWidget  *gdu_create_linux_lvm2_volume_dialog_new            (GtkWindow                *parent,
+                                                                GduPresentable           *presentable,
+                                                                guint64                   max_size,
+                                                                GduFormatDialogFlags      flags);
+guint64     gdu_create_linux_lvm2_volume_dialog_get_size       (GduCreateLinuxLvm2VolumeDialog *dialog);
+guint64     gdu_create_linux_lvm2_volume_dialog_get_max_size   (GduCreateLinuxLvm2VolumeDialog *dialog);
+
+G_END_DECLS
+
+#endif  /* __GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG_H */
+
diff --git a/src/gdu-gtk/gdu-gtk-types.h b/src/gdu-gtk/gdu-gtk-types.h
index f10d032..d0845ab 100644
--- a/src/gdu-gtk/gdu-gtk-types.h
+++ b/src/gdu-gtk/gdu-gtk-types.h
@@ -33,35 +33,36 @@
 
 G_BEGIN_DECLS
 
-typedef struct GduSample                    GduSample;
-typedef struct GduColor                     GduColor;
-typedef struct GduCurve                     GduCurve;
-typedef struct GduGraph                     GduGraph;
-typedef struct GduTimeLabel                 GduTimeLabel;
-typedef struct GduAtaSmartDialog            GduAtaSmartDialog;
-typedef struct GduSpinner                   GduSpinner;
-typedef struct GduPoolTreeModel             GduPoolTreeModel;
-typedef struct GduPoolTreeView              GduPoolTreeView;
-typedef struct GduCreateLinuxMdDialog       GduCreateLinuxMdDialog;
-typedef struct GduSizeWidget                GduSizeWidget;
-typedef struct GduVolumeGrid                GduVolumeGrid;
-typedef struct GduDetailsTable              GduDetailsTable;
-typedef struct GduDetailsElement            GduDetailsElement;
-typedef struct GduErrorDialog               GduErrorDialog;
-typedef struct GduConfirmationDialog        GduConfirmationDialog;
-typedef struct GduButtonElement             GduButtonElement;
-typedef struct GduButtonTable               GduButtonTable;
-typedef struct GduDialog                    GduDialog;
-typedef struct GduEditPartitionDialog       GduEditPartitionDialog;
-typedef struct GduFormatDialog              GduFormatDialog;
-typedef struct GduPartitionDialog           GduPartitionDialog;
-typedef struct GduCreatePartitionDialog     GduCreatePartitionDialog;
-typedef struct GduEditNameDialog            GduEditNameDialog;
-typedef struct GduDiskSelectionWidget       GduDiskSelectionWidget;
-typedef struct GduAddComponentLinuxMdDialog GduAddComponentLinuxMdDialog;
-typedef struct GduEditLinuxMdDialog         GduEditLinuxMdDialog;
-typedef struct GduDriveBenchmarkDialog      GduDriveBenchmarkDialog;
-typedef struct GduConnectToServerDialog     GduConnectToServerDialog;
+typedef struct GduSample                      GduSample;
+typedef struct GduColor                       GduColor;
+typedef struct GduCurve                       GduCurve;
+typedef struct GduGraph                       GduGraph;
+typedef struct GduTimeLabel                   GduTimeLabel;
+typedef struct GduAtaSmartDialog              GduAtaSmartDialog;
+typedef struct GduSpinner                     GduSpinner;
+typedef struct GduPoolTreeModel               GduPoolTreeModel;
+typedef struct GduPoolTreeView                GduPoolTreeView;
+typedef struct GduCreateLinuxMdDialog         GduCreateLinuxMdDialog;
+typedef struct GduSizeWidget                  GduSizeWidget;
+typedef struct GduVolumeGrid                  GduVolumeGrid;
+typedef struct GduDetailsTable                GduDetailsTable;
+typedef struct GduDetailsElement              GduDetailsElement;
+typedef struct GduErrorDialog                 GduErrorDialog;
+typedef struct GduConfirmationDialog          GduConfirmationDialog;
+typedef struct GduButtonElement               GduButtonElement;
+typedef struct GduButtonTable                 GduButtonTable;
+typedef struct GduDialog                      GduDialog;
+typedef struct GduEditPartitionDialog         GduEditPartitionDialog;
+typedef struct GduFormatDialog                GduFormatDialog;
+typedef struct GduPartitionDialog             GduPartitionDialog;
+typedef struct GduCreatePartitionDialog       GduCreatePartitionDialog;
+typedef struct GduCreateLinuxLvm2VolumeDialog GduCreateLinuxLvm2VolumeDialog;
+typedef struct GduEditNameDialog              GduEditNameDialog;
+typedef struct GduDiskSelectionWidget         GduDiskSelectionWidget;
+typedef struct GduAddComponentLinuxMdDialog   GduAddComponentLinuxMdDialog;
+typedef struct GduEditLinuxMdDialog           GduEditLinuxMdDialog;
+typedef struct GduDriveBenchmarkDialog        GduDriveBenchmarkDialog;
+typedef struct GduConnectToServerDialog       GduConnectToServerDialog;
 
 G_END_DECLS
 
diff --git a/src/gdu/gdu-callbacks.h b/src/gdu/gdu-callbacks.h
index ffd34b9..f77af80 100644
--- a/src/gdu/gdu-callbacks.h
+++ b/src/gdu/gdu-callbacks.h
@@ -188,6 +188,11 @@ typedef void (*GduPoolLinuxLvm2LVRemoveCompletedFunc) (GduPool    *pool,
                                                        GError     *error,
                                                        gpointer    user_data);
 
+typedef void (*GduPoolLinuxLvm2LVCreateCompletedFunc) (GduPool    *pool,
+                                                       char       *create_logical_volume_object_path,
+                                                       GError     *error,
+                                                       gpointer    user_data);
+
 /* ---------------------------------------------------------------------------------------------------- */
 /* GduDrive */
 
diff --git a/src/gdu/gdu-linux-lvm2-volume-group.c b/src/gdu/gdu-linux-lvm2-volume-group.c
index 8b94917..430b703 100644
--- a/src/gdu/gdu-linux-lvm2-volume-group.c
+++ b/src/gdu/gdu-linux-lvm2-volume-group.c
@@ -560,6 +560,26 @@ gdu_linux_lvm2_volume_group_get_uuid (GduLinuxLvm2VolumeGroup *vg)
         return vg->priv->uuid;
 }
 
+guint
+gdu_linux_lvm2_volume_group_get_num_lvs (GduLinuxLvm2VolumeGroup *vg)
+{
+        guint ret;
+        gchar **lvs;
+
+        ret = 0;
+
+        if (vg->priv->pv == NULL)
+                goto out;
+
+        lvs = gdu_device_linux_lvm2_pv_get_group_logical_volumes (vg->priv->pv);
+
+        if (lvs != NULL)
+                ret = g_strv_length (lvs);
+
+ out:
+        return ret;
+}
+
 gboolean
 gdu_linux_lvm2_volume_group_get_lv_info (GduLinuxLvm2VolumeGroup  *vg,
                                          const gchar              *lv_uuid,
@@ -625,3 +645,52 @@ gdu_linux_lvm2_volume_group_get_lv_info (GduLinuxLvm2VolumeGroup  *vg,
         }
         return ret;
 }
+
+static gboolean
+lv_name_exists (GduLinuxLvm2VolumeGroup *vg, const gchar *name)
+{
+        gboolean ret;
+        gchar **lvs;
+        guint n;
+
+        ret = FALSE;
+
+        if (vg->priv->pv == NULL)
+                goto out;
+
+        lvs = gdu_device_linux_lvm2_pv_get_group_logical_volumes (vg->priv->pv);
+        for (n = 0; lvs != NULL && lvs[n] != NULL; n++) {
+                gchar **tokens;
+                guint m;
+
+                tokens = g_strsplit (lvs[n], ";", 0);
+
+                for (m = 0; tokens[m] != NULL; m++) {
+                        /* TODO: we need to unescape values */
+                        if (g_str_has_prefix (tokens[m], "name=") && g_strcmp0 (tokens[m] + 5, name) == 0) {
+                                g_strfreev (tokens);
+                                ret = TRUE;
+                                goto out;
+                        }
+                }
+                g_strfreev (tokens);
+        }
+
+ out:
+        return ret;
+}
+
+/* Computes the next available Logical Volume name */
+gchar *
+gdu_linux_lvm2_volume_group_get_compute_new_lv_name (GduLinuxLvm2VolumeGroup *vg)
+{
+        GString *s;
+
+        s = g_string_new (NULL);
+        g_string_append_printf (s, "Logical_Volume_%02d", gdu_linux_lvm2_volume_group_get_num_lvs (vg));
+
+        while (lv_name_exists (vg, s->str))
+                g_string_append_c (s, '_');
+
+        return g_string_free (s, FALSE);
+}
diff --git a/src/gdu/gdu-linux-lvm2-volume-group.h b/src/gdu/gdu-linux-lvm2-volume-group.h
index db48b98..b065fb6 100644
--- a/src/gdu/gdu-linux-lvm2-volume-group.h
+++ b/src/gdu/gdu-linux-lvm2-volume-group.h
@@ -64,11 +64,13 @@ GType                         gdu_linux_lvm2_volume_group_get_type      (void);
 const gchar                  *gdu_linux_lvm2_volume_group_get_uuid      (GduLinuxLvm2VolumeGroup  *vg);
 GduLinuxLvm2VolumeGroupState  gdu_linux_lvm2_volume_group_get_state     (GduLinuxLvm2VolumeGroup  *vg);
 GduDevice                    *gdu_linux_lvm2_volume_group_get_pv_device (GduLinuxLvm2VolumeGroup  *vg);
+guint                         gdu_linux_lvm2_volume_group_get_num_lvs   (GduLinuxLvm2VolumeGroup  *vg);
 gboolean                      gdu_linux_lvm2_volume_group_get_lv_info   (GduLinuxLvm2VolumeGroup  *vg,
                                                                          const gchar              *lv_uuid,
                                                                          guint                    *out_position,
                                                                          gchar                   **out_name,
                                                                          guint64                  *out_size);
+gchar                        *gdu_linux_lvm2_volume_group_get_compute_new_lv_name (GduLinuxLvm2VolumeGroup  *vg);
 
 G_END_DECLS
 
diff --git a/src/gdu/gdu-pool.c b/src/gdu/gdu-pool.c
index 217cfed..4000fee 100644
--- a/src/gdu/gdu-pool.c
+++ b/src/gdu/gdu-pool.c
@@ -2984,15 +2984,15 @@ void
 gdu_pool_op_linux_lvm2_lv_remove (GduPool *pool,
                                   const gchar *group_uuid,
                                   const gchar *uuid,
-                                  GduPoolLinuxLvm2LVSetNameCompletedFunc callback,
+                                  GduPoolLinuxLvm2LVRemoveCompletedFunc callback,
                                   gpointer user_data)
 {
-        LinuxLvm2LVSetNameData *data;
+        LinuxLvm2LVRemoveData *data;
         char *options[16];
 
         options[0] = NULL;
 
-        data = g_new0 (LinuxLvm2LVSetNameData, 1);
+        data = g_new0 (LinuxLvm2LVRemoveData, 1);
         data->pool = g_object_ref (pool);
         data->callback = callback;
         data->user_data = user_data;
@@ -3007,6 +3007,82 @@ gdu_pool_op_linux_lvm2_lv_remove (GduPool *pool,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+typedef struct {
+        GduPool *pool;
+        GduPoolLinuxLvm2LVCreateCompletedFunc callback;
+        gpointer user_data;
+} LinuxLvm2LVCreateData;
+
+static void
+op_linux_lvm2_lv_create_cb (DBusGProxy *proxy,
+                            char       *create_logical_volume_object_path,
+                            GError *error,
+                            gpointer user_data)
+{
+        LinuxLvm2LVCreateData *data = user_data;
+        _gdu_error_fixup (error);
+        if (data->callback != NULL)
+                data->callback (data->pool, create_logical_volume_object_path, error, data->user_data);
+        g_object_unref (data->pool);
+        g_free (data);
+}
+
+void
+gdu_pool_op_linux_lvm2_lv_create (GduPool *pool,
+                                  const gchar *group_uuid,
+                                  const gchar *name,
+                                  guint64 size,
+                                  guint num_stripes,
+                                  guint64 stripe_size,
+                                  guint num_mirrors,
+                                  const char                             *fstype,
+                                  const char                             *fslabel,
+                                  const char                             *encrypt_passphrase,
+                                  gboolean                                fs_take_ownership,
+                                  GduPoolLinuxLvm2LVCreateCompletedFunc callback,
+                                  gpointer user_data)
+{
+        LinuxLvm2LVCreateData *data;
+        char *options[16];
+        char *fsoptions[16];
+        guint n;
+
+        data = g_new0 (LinuxLvm2LVCreateData, 1);
+        data->pool = g_object_ref (pool);
+        data->callback = callback;
+        data->user_data = user_data;
+
+        options[0] = NULL;
+
+        n = 0;
+        if (fslabel != NULL && strlen (fslabel) > 0) {
+                fsoptions[n++] = g_strdup_printf ("label=%s", fslabel);
+        }
+        if (encrypt_passphrase != NULL && strlen (encrypt_passphrase) > 0) {
+                fsoptions[n++] = g_strdup_printf ("luks_encrypt=%s", encrypt_passphrase);
+        }
+        if (fs_take_ownership) {
+                fsoptions[n++] = g_strdup_printf ("take_ownership_uid=%d", getuid ());
+                fsoptions[n++] = g_strdup_printf ("take_ownership_gid=%d", getgid ());
+        }
+        fsoptions[n] = NULL;
+
+        org_freedesktop_UDisks_linux_lvm2_lv_create_async (pool->priv->proxy,
+                                                           group_uuid,
+                                                           name,
+                                                           size,
+                                                           num_stripes,
+                                                           stripe_size,
+                                                           num_mirrors,
+                                                           (const char **) options,
+                                                           fstype,
+                                                           (const char **) fsoptions,
+                                                           op_linux_lvm2_lv_create_cb,
+                                                           data);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /**
  * gdu_pool_get_daemon_version:
  * @pool: A #GduPool.
diff --git a/src/gdu/gdu-pool.h b/src/gdu/gdu-pool.h
index b93c1fb..132be60 100644
--- a/src/gdu/gdu-pool.h
+++ b/src/gdu/gdu-pool.h
@@ -168,6 +168,20 @@ void gdu_pool_op_linux_lvm2_lv_remove (GduPool *pool,
                                        GduPoolLinuxLvm2LVRemoveCompletedFunc callback,
                                        gpointer user_data);
 
+void gdu_pool_op_linux_lvm2_lv_create (GduPool *pool,
+                                       const gchar *group_uuid,
+                                       const gchar *name,
+                                       guint64 size,
+                                       guint num_stripes,
+                                       guint64 stripe_size,
+                                       guint num_mirrors,
+                                       const char                             *fstype,
+                                       const char                             *fslabel,
+                                       const char                             *encrypt_passphrase,
+                                       gboolean                                fs_take_ownership,
+                                       GduPoolLinuxLvm2LVCreateCompletedFunc callback,
+                                       gpointer user_data);
+
 G_END_DECLS
 
 #endif /* __GDU_POOL_H */
diff --git a/src/palimpsest/gdu-section-volumes.c b/src/palimpsest/gdu-section-volumes.c
index 04b170b..72f87e3 100644
--- a/src/palimpsest/gdu-section-volumes.c
+++ b/src/palimpsest/gdu-section-volumes.c
@@ -1392,26 +1392,178 @@ on_fs_mount_point_element_activated (GduDetailsElement *element,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+typedef struct {
+        GduShell *shell;
+        GduPresentable *presentable;
+        char *encrypt_passphrase;
+        gboolean save_in_keyring;
+        gboolean save_in_keyring_session;
+} CreateLinuxLvm2LVData;
+
+static void
+create_linux_lvm2_lv_data_free (CreateLinuxLvm2LVData *data)
+{
+        if (data->shell != NULL)
+                g_object_unref (data->shell);
+        if (data->presentable != NULL)
+                g_object_unref (data->presentable);
+        if (data->encrypt_passphrase != NULL) {
+                memset (data->encrypt_passphrase, '\0', strlen (data->encrypt_passphrase));
+                g_free (data->encrypt_passphrase);
+        }
+        g_free (data);
+}
+
+static void
+lvm2_lv_create_op_callback (GduPool    *pool,
+                            gchar      *created_device_object_path,
+                            GError     *error,
+                            gpointer    user_data)
+{
+        CreateLinuxLvm2LVData *data = user_data;
+
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new (GTK_WINDOW (gdu_shell_get_toplevel (data->shell)),
+                                               data->presentable,
+                                               _("Error creating Logical Volume"),
+                                               error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
+        } else {
+                if (data->encrypt_passphrase != NULL) {
+                        GduDevice *cleartext_device;
+
+                        cleartext_device = gdu_pool_get_by_object_path (pool, created_device_object_path);
+                        if (cleartext_device != NULL) {
+                                const gchar *cryptotext_device_object_path;
+
+                                cryptotext_device_object_path = gdu_device_luks_cleartext_get_slave (cleartext_device);
+                                if (cryptotext_device_object_path != NULL) {
+                                        GduDevice *cryptotext_device;
+
+                                        cryptotext_device = gdu_pool_get_by_object_path (pool,
+                                                                                         cryptotext_device_object_path);
+                                        if (cryptotext_device != NULL) {
+                                                /* now set the passphrase if requested */
+                                                if (data->save_in_keyring || data->save_in_keyring_session) {
+                                                        gdu_util_save_secret (cryptotext_device,
+                                                                              data->encrypt_passphrase,
+                                                                              data->save_in_keyring_session);
+                                                }
+                                                g_object_unref (cryptotext_device);
+                                        }
+                                }
+                                g_object_unref (cleartext_device);
+                        }
+                }
+                g_free (created_device_object_path);
+        }
+
+        if (data != NULL)
+                create_linux_lvm2_lv_data_free (data);
+}
+
 static void
 on_lvm2_create_lv_button_clicked (GduButtonElement *button_element,
                                   gpointer          user_data)
 {
         GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+        GduPresentable *v;
+        GduPresentable *vg;
+        GduPool *pool;
+        GtkWindow *toplevel;
         GtkWidget *dialog;
-        GError *error;
+        gint response;
+        GduFormatDialogFlags flags;
+        const gchar *vg_uuid;
+
+        v = NULL;
+        pool = NULL;
+        dialog = NULL;
 
-        error = g_error_new (GDU_ERROR,
-                             GDU_ERROR_NOT_SUPPORTED,
-                             _("Not yet implemented"));
-        dialog = gdu_error_dialog_new (GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section)))),
-                                       gdu_section_get_presentable (GDU_SECTION (section)),
-                                       _("There was an error creating a Logical Volume"),
-                                       error);
+        v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+        if (v == NULL || !GDU_IS_VOLUME_HOLE (v))
+                goto out;
+
+        vg = gdu_section_get_presentable (GDU_SECTION (section));
+        vg_uuid = gdu_linux_lvm2_volume_group_get_uuid (GDU_LINUX_LVM2_VOLUME_GROUP (vg));
+
+        pool = gdu_presentable_get_pool (v);
+
+        flags = GDU_FORMAT_DIALOG_FLAGS_NONE;
+
+        toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))));
+        dialog = gdu_create_linux_lvm2_volume_dialog_new (toplevel,
+                                                          vg,
+                                                          gdu_presentable_get_size (v),
+                                                          flags);
         gtk_widget_show_all (dialog);
-        gtk_window_present (GTK_WINDOW (dialog));
-        gtk_dialog_run (GTK_DIALOG (dialog));
-        gtk_widget_destroy (dialog);
-        g_error_free (error);
+        response = gtk_dialog_run (GTK_DIALOG (dialog));
+        gtk_widget_hide (dialog);
+        if (response == GTK_RESPONSE_OK) {
+                CreateLinuxLvm2LVData *data;
+                gchar *volume_name;
+                gchar *fs_type;
+                gchar *fs_label;
+                gboolean fs_take_ownership;
+                guint64 size;
+
+                data = g_new0 (CreateLinuxLvm2LVData, 1);
+                data->shell = g_object_ref (gdu_section_get_shell (GDU_SECTION (section)));
+                data->presentable = g_object_ref (vg);
+
+                if (gdu_format_dialog_get_encrypt (GDU_FORMAT_DIALOG (dialog))) {
+                        data->encrypt_passphrase = gdu_util_dialog_ask_for_new_secret (GTK_WIDGET (toplevel),
+                                                                                       &data->save_in_keyring,
+                                                                                       &data->save_in_keyring_session);
+                        if (data->encrypt_passphrase == NULL) {
+                                create_linux_lvm2_lv_data_free (data);
+                                goto out;
+                        }
+                }
+
+                /* For now, just use a generic LV name - maybe we should include a GtkEntry widget in
+                 * the GduCreateLinuxLvm2LVDialog, maybe not.
+                 */
+                volume_name = gdu_linux_lvm2_volume_group_get_compute_new_lv_name (GDU_LINUX_LVM2_VOLUME_GROUP (vg));
+
+                fs_type = gdu_format_dialog_get_fs_type (GDU_FORMAT_DIALOG (dialog));
+                fs_label = gdu_format_dialog_get_fs_label (GDU_FORMAT_DIALOG (dialog));
+                fs_take_ownership = gdu_format_dialog_get_take_ownership (GDU_FORMAT_DIALOG (dialog));
+
+                size = gdu_create_linux_lvm2_volume_dialog_get_size (GDU_CREATE_LINUX_LVM2_VOLUME_DIALOG (dialog));
+
+                /* TODO: include widgets for configuring striping and mirroring */
+
+                gdu_pool_op_linux_lvm2_lv_create (pool,
+                                                  vg_uuid,
+                                                  volume_name,
+                                                  size,
+                                                  0, /* num_stripes */
+                                                  0, /* stripe_size */
+                                                  0, /* num_mirrors */
+                                                  fs_type,
+                                                  fs_label,
+                                                  data->encrypt_passphrase,
+                                                  fs_take_ownership,
+                                                  lvm2_lv_create_op_callback,
+                                                  data);
+
+                g_free (fs_type);
+                g_free (fs_label);
+                g_free (volume_name);
+        }
+ out:
+        if (dialog != NULL)
+                gtk_widget_destroy (dialog);
+        if (v != NULL)
+                g_object_unref (v);
+        if (pool != NULL)
+                g_object_unref (pool);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -2166,7 +2318,7 @@ gdu_section_volumes_constructed (GObject *object)
         section->priv->fs_mount_button = button_element;
 
         button_element = gdu_button_element_new ("gdu-unmount",
-                                                 _("_Unmount Volume"),
+                                                 _("Un_mount Volume"),
                                                  _("Unmount the volume"));
         g_signal_connect (button_element,
                           "clicked",
@@ -2247,7 +2399,7 @@ gdu_section_volumes_constructed (GObject *object)
         section->priv->luks_lock_button = button_element;
 
         button_element = gdu_button_element_new ("gdu-encrypted-unlock",
-                                                 _("_Unlock Volume"),
+                                                 _("Un_lock Volume"),
                                                  _("Make encrypted data available"));
         g_signal_connect (button_element,
                           "clicked",



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]