[gnome-disk-utility/udisks2-port] Add a way to create disk images
- From: David Zeuthen <davidz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility/udisks2-port] Add a way to create disk images
- Date: Thu, 1 Dec 2011 17:19:53 +0000 (UTC)
commit 5296a62f3a50f8424ef1df00cad437195c8bed25
Author: David Zeuthen <davidz redhat com>
Date: Thu Dec 1 12:18:28 2011 -0500
Add a way to create disk images
See
http://people.freedesktop.org/~david/gdu2-create-disk-image-1.png
http://people.freedesktop.org/~david/gdu2-create-disk-image-2.png
http://people.freedesktop.org/~david/gdu2-create-disk-image-3.png
http://people.freedesktop.org/~david/gdu2-create-disk-image-4.png
http://people.freedesktop.org/~david/gdu2-create-disk-image-5.png
http://people.freedesktop.org/~david/gdu2-create-disk-image-6.png
http://people.freedesktop.org/~david/gdu2-create-disk-image-7.png
Signed-off-by: David Zeuthen <davidz redhat com>
data/ui/Makefile.am | 1 +
data/ui/create-disk-image-dialog.ui | 223 +++++++++++++
data/ui/palimpsest.ui | 20 ++-
src/palimpsest/Makefile.am | 1 +
src/palimpsest/gducreatediskimagedialog.c | 494 +++++++++++++++++++++++++++++
src/palimpsest/gducreatediskimagedialog.h | 36 ++
src/palimpsest/gduwindow.c | 83 ++++-
7 files changed, 844 insertions(+), 14 deletions(-)
---
diff --git a/data/ui/Makefile.am b/data/ui/Makefile.am
index 9952286..544f3be 100644
--- a/data/ui/Makefile.am
+++ b/data/ui/Makefile.am
@@ -17,6 +17,7 @@ ui_DATA = \
create-partition-dialog.ui \
filesystem-create.ui \
format-disk-dialog.ui \
+ create-disk-image-dialog.ui \
$(NULL)
clean-local :
diff --git a/data/ui/create-disk-image-dialog.ui b/data/ui/create-disk-image-dialog.ui
new file mode 100644
index 0000000..9698d26
--- /dev/null
+++ b/data/ui/create-disk-image-dialog.ui
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkDialog" id="create-disk-image-dialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">12</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes"><big>Create Disk Image</big></property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="start_copying_button">
+ <property name="label" translatable="yes">_Start Copying...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="notebook">
+ <property name="can_focus">False</property>
+ <property name="margin_left">12</property>
+ <property name="show_tabs">False</property>
+ <property name="show_border">False</property>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">12</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">_Name</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">destination_name_entry</property>
+ <attributes>
+ <attribute name="foreground" value="#555555555555"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Save in _folder</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">destination_folder_fcbutton</property>
+ <attributes>
+ <attribute name="foreground" value="#555555555555"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="destination_name_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">â</property>
+ <property name="activates_default">True</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFileChooserButton" id="destination_folder_fcbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="action">select-folder</property>
+ <property name="local_only">False</property>
+ <property name="title" translatable="yes">Select a Folder</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">24</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="copying_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Copying data to disk image...</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="copying_progressbar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">button1</action-widget>
+ <action-widget response="-5">start_copying_button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/data/ui/palimpsest.ui b/data/ui/palimpsest.ui
index 65343bc..23f8241 100644
--- a/data/ui/palimpsest.ui
+++ b/data/ui/palimpsest.ui
@@ -67,11 +67,20 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
+ <object class="GtkMenuItem" id="generic-menu-item-create-disk-image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">Create Disk Image...</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
<object class="GtkMenuItem" id="generic-menu-item-format-disk">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
- <property name="label" translatable="yes">Format Disk...</property>
+ <property name="label" translatable="yes">Format Whole Disk...</property>
<property name="use_underline">True</property>
</object>
</child>
@@ -92,6 +101,15 @@
</object>
</child>
<child>
+ <object class="GtkMenuItem" id="generic-menu-item-create-volume-image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">Create Disk Image from Volume...</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
<object class="GtkMenuItem" id="generic-menu-item-format-volume">
<property name="visible">True</property>
<property name="can_focus">False</property>
diff --git a/src/palimpsest/Makefile.am b/src/palimpsest/Makefile.am
index 0975e8c..43dcc5e 100644
--- a/src/palimpsest/Makefile.am
+++ b/src/palimpsest/Makefile.am
@@ -41,6 +41,7 @@ palimpsest_SOURCES = \
gducreatepartitiondialog.h gducreatepartitiondialog.c \
gducreatefilesystemwidget.h gducreatefilesystemwidget.c \
gduformatdiskdialog.h gduformatdiskdialog.c \
+ gducreatediskimagedialog.h gducreatediskimagedialog.c \
$(enum_built_sources) \
$(NULL)
diff --git a/src/palimpsest/gducreatediskimagedialog.c b/src/palimpsest/gducreatediskimagedialog.c
new file mode 100644
index 0000000..d8491e9
--- /dev/null
+++ b/src/palimpsest/gducreatediskimagedialog.c
@@ -0,0 +1,494 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gio/gunixfdlist.h>
+#include <gio/gunixinputstream.h>
+
+#include "gduapplication.h"
+#include "gduwindow.h"
+#include "gducreatediskimagedialog.h"
+#include "gduvolumegrid.h"
+#include "gduutils.h"
+#include "gducreatefilesystemwidget.h"
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+#define BUFFER_SIZE (1024*1024)
+
+typedef struct
+{
+ volatile gint ref_count;
+
+ GduWindow *window;
+ UDisksObject *object;
+ UDisksBlock *block;
+ UDisksDrive *drive;
+
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+
+ GtkWidget *notebook;
+ GtkWidget *start_copying_button;
+ GtkWidget *destination_name_entry;
+ GtkWidget *destination_name_fcbutton;
+ GtkWidget *copying_progressbar;
+ GtkWidget *copying_label;
+
+ GCancellable *cancellable;
+ GInputStream *block_stream;
+ GFile *output_file;
+ GFileOutputStream *output_file_stream;
+ guint64 block_size;
+ gboolean delete_on_free;
+
+ guchar *buffer;
+ guint64 total_bytes_read;
+ guint64 buffer_bytes_written;
+ guint64 buffer_bytes_to_write;
+} CreateDiskImageData;
+
+static CreateDiskImageData *
+create_disk_image_data_ref (CreateDiskImageData *data)
+{
+ g_atomic_int_inc (&data->ref_count);
+ return data;
+}
+
+static void
+create_disk_image_data_unref (CreateDiskImageData *data)
+{
+ if (g_atomic_int_dec_and_test (&data->ref_count))
+ {
+ if (data->dialog != NULL)
+ {
+ gtk_widget_hide (data->dialog);
+ gtk_widget_destroy (data->dialog);
+ }
+ g_clear_object (&data->cancellable);
+ g_clear_object (&data->output_file_stream);
+ g_clear_object (&data->block_stream);
+ if (data->delete_on_free)
+ {
+ GError *error = NULL;
+ if (!g_file_delete (data->output_file, NULL, &error))
+ {
+ g_warning ("Error deleting file: %s (%s, %d)",
+ error->message, g_quark_to_string (error->domain), error->code);
+ g_error_free (error);
+ }
+ }
+ g_object_unref (data->window);
+ g_object_unref (data->object);
+ g_object_unref (data->block);
+ g_clear_object (&data->drive);
+ if (data->builder != NULL)
+ g_object_unref (data->builder);
+ g_free (data->buffer);
+ g_free (data);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+create_disk_image_data_complete (CreateDiskImageData *data)
+{
+ g_cancellable_cancel (data->cancellable);
+ gtk_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_CANCEL);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+create_disk_image_populate (CreateDiskImageData *data)
+{
+ gchar *device_name;
+ gchar *now_string;
+ gchar *s;
+ guint n;
+ GTimeZone *tz;
+ GDateTime *now;
+ const gchar *folder;
+
+ device_name = udisks_block_dup_preferred_device (data->block);
+ if (g_str_has_prefix (device_name, "/dev/"))
+ memmove (device_name, device_name + 5, strlen (device_name) - 5 + 1);
+ for (n = 0; device_name[n] != '\0'; n++)
+ {
+ if (device_name[n] == '/')
+ device_name[n] = '_';
+ }
+
+ tz = g_time_zone_new_local ();
+ now = g_date_time_new_now (tz);
+ now_string = g_date_time_format (now, "%Y-%m-%d %H%M");
+
+ /* Translators: The suggested name for the disk image to create.
+ * The first %s is a name for the disk (e.g. 'sdb').
+ * The second %s is today's date and time, e.g. "March 2, 1976 6:25AM".
+ */
+ s = g_strdup_printf (_("Disk Image of %s (%s).img"),
+ device_name,
+ now_string);
+ gtk_entry_set_text (GTK_ENTRY (data->destination_name_entry), s);
+ g_free (s);
+ g_free (device_name);
+ g_date_time_unref (now);
+ g_time_zone_unref (tz);
+ g_free (now_string);
+
+ /* Defaults to the "Documents" folder */
+ folder = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS);
+ if (folder != NULL)
+ {
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (data->destination_name_fcbutton), folder);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void copy_more (CreateDiskImageData *data);
+
+static void write_more (CreateDiskImageData *data);
+
+static void
+write_cb (GOutputStream *output_stream,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CreateDiskImageData *data = user_data;
+ GError *error;
+ gssize bytes_written;
+
+ error = NULL;
+ bytes_written = g_output_stream_write_finish (output_stream, res, &error);
+ if (error != NULL)
+ {
+ if (!(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED))
+ gdu_window_show_error (data->window,
+ _("Error writing to backup image"), error);
+ g_error_free (error);
+ create_disk_image_data_complete (data);
+ goto out;
+ }
+
+ data->buffer_bytes_written += bytes_written;
+ data->buffer_bytes_to_write -= bytes_written;
+
+ /* update progress bar */
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (data->copying_progressbar),
+ ((gdouble) data->total_bytes_read) / ((gdouble) data->block_size));
+
+ /* TODO: we should do fancy stuff like printing the estimated speed and time remaining */
+
+ write_more (data);
+
+ out:
+ create_disk_image_data_unref (data);
+}
+
+static void
+write_more (CreateDiskImageData *data)
+{
+ if (data->buffer_bytes_to_write == 0)
+ {
+ copy_more (data);
+ }
+ else
+ {
+ g_output_stream_write_async (G_OUTPUT_STREAM (data->output_file_stream),
+ data->buffer + data->buffer_bytes_written,
+ data->buffer_bytes_to_write,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ (GAsyncReadyCallback) write_cb,
+ create_disk_image_data_ref (data));
+ }
+}
+
+
+static void
+read_cb (GInputStream *input_stream,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CreateDiskImageData *data = user_data;
+ GError *error;
+ gssize bytes_read;
+
+ error = NULL;
+ bytes_read = g_input_stream_read_finish (input_stream, res, &error);
+ if (error != NULL)
+ {
+ gchar *s;
+ s = g_strdup_printf (_("Error reading from offset %" G_GUINT64_FORMAT " of device %s"),
+ (guint64) data->total_bytes_read,
+ udisks_block_get_preferred_device (data->block));
+ if (!(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED))
+ gdu_window_show_error (data->window, s, error);
+ g_free (s);
+ g_error_free (error);
+ create_disk_image_data_complete (data);
+ goto out;
+ }
+
+ data->total_bytes_read += bytes_read;
+
+ data->buffer_bytes_written = 0;
+ data->buffer_bytes_to_write = bytes_read;
+ write_more (data);
+
+ out:
+ create_disk_image_data_unref (data);
+}
+
+static void
+copy_more (CreateDiskImageData *data)
+{
+ guint64 bytes_to_read;
+
+ bytes_to_read = data->block_size - data->total_bytes_read;
+ if (bytes_to_read == 0)
+ {
+ data->delete_on_free = FALSE;
+ create_disk_image_data_complete (data);
+ goto out;
+ }
+ if (bytes_to_read > BUFFER_SIZE)
+ bytes_to_read = BUFFER_SIZE;
+
+ g_input_stream_read_async (data->block_stream,
+ data->buffer,
+ bytes_to_read,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ (GAsyncReadyCallback) read_cb,
+ create_disk_image_data_ref (data));
+ out:
+ ;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+open_cb (UDisksBlock *block,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CreateDiskImageData *data = user_data;
+ GError *error;
+ GUnixFDList *fd_list = NULL;
+ GVariant *fd_index = NULL;
+ int fd;
+
+ error = NULL;
+ if (!udisks_block_call_open_for_backup_finish (block,
+ &fd_index,
+ &fd_list,
+ res,
+ &error))
+ {
+ if (!(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED))
+ gdu_window_show_error (data->window, _("Error opening device"), error);
+ g_error_free (error);
+ create_disk_image_data_complete (data);
+ goto out;
+ }
+
+ fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_index), NULL);
+ data->block_stream = g_unix_input_stream_new (fd, TRUE);
+
+ /* Alright, time to start copying! */
+ data->cancellable = g_cancellable_new ();
+ data->buffer = g_new0 (guchar, BUFFER_SIZE);
+ copy_more (data);
+
+ out:
+ if (fd_index != NULL)
+ g_variant_unref (fd_index);
+ g_clear_object (&fd_list);
+}
+
+/* returns TRUE if OK to overwrite or file doesn't exist */
+static gboolean
+check_overwrite (CreateDiskImageData *data)
+{
+ GFile *folder = NULL;
+ const gchar *name;
+ gboolean ret = TRUE;
+ GFile *file = NULL;
+ GFileInfo *folder_info = NULL;
+ GtkWidget *dialog;
+ gint response;
+
+ name = gtk_entry_get_text (GTK_ENTRY (data->destination_name_entry));
+ folder = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (data->destination_name_fcbutton));
+ file = g_file_get_child (folder, name);
+ if (!g_file_query_exists (file, NULL))
+ goto out;
+
+ folder_info = g_file_query_info (folder,
+ G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+ if (folder_info == NULL)
+ goto out;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (data->dialog),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("A file named \"%s\" already exists. Do you want to replace it?"),
+ name);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("The file already exists in \"%s\". Replacing it will "
+ "overwrite its contents."),
+ g_file_info_get_display_name (folder_info));
+ gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Replace"), GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT,
+ GTK_RESPONSE_CANCEL,
+ -1);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response != GTK_RESPONSE_ACCEPT)
+ ret = FALSE;
+
+ gtk_widget_destroy (dialog);
+
+ out:
+ g_clear_object (&folder_info);
+ g_clear_object (&file);
+ g_clear_object (&folder);
+ return ret;
+}
+
+static gboolean
+start_copying (CreateDiskImageData *data)
+{
+ gboolean ret = TRUE;
+ const gchar *name;
+ GFile *folder;
+ GError *error;
+
+ name = gtk_entry_get_text (GTK_ENTRY (data->destination_name_entry));
+ folder = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (data->destination_name_fcbutton));
+
+ error = NULL;
+ data->output_file = g_file_get_child (folder, name);
+ data->output_file_stream = g_file_replace (data->output_file,
+ NULL, /* etag */
+ FALSE, /* make_backup */
+ G_FILE_CREATE_NONE,
+ NULL,
+ &error);
+ if (data->output_file_stream == NULL)
+ {
+ if (!(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED))
+ gdu_window_show_error (data->window, _("Error opening file for writing"), error);
+ g_error_free (error);
+ g_object_unref (folder);
+ create_disk_image_data_complete (data);
+ ret = FALSE;
+ goto out;
+ }
+ data->delete_on_free = TRUE;
+
+ data->block_size = udisks_block_get_size (data->block);
+ udisks_block_call_open_for_backup (data->block,
+ g_variant_new ("a{sv}", NULL), /* options */
+ NULL, /* fd_list */
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) open_cb,
+ data);
+
+ out:
+ g_clear_object (&folder);
+ return ret;
+}
+
+void
+gdu_create_disk_image_dialog_show (GduWindow *window,
+ UDisksObject *object)
+{
+ CreateDiskImageData *data;
+ gint response;
+ gchar *s;
+
+ data = g_new0 (CreateDiskImageData, 1);
+ data->ref_count = 1;
+ data->window = g_object_ref (window);
+ data->object = g_object_ref (object);
+ data->block = udisks_object_get_block (object);
+ g_assert (data->block != NULL);
+ data->drive = udisks_client_get_drive_for_block (gdu_window_get_client (window), data->block);
+
+ data->dialog = gdu_application_new_widget (gdu_window_get_application (window),
+ "create-disk-image-dialog.ui",
+ "create-disk-image-dialog",
+ &data->builder);
+ data->notebook = GTK_WIDGET (gtk_builder_get_object (data->builder, "notebook"));
+ data->start_copying_button = GTK_WIDGET (gtk_builder_get_object (data->builder, "start_copying_button"));
+ data->destination_name_entry = GTK_WIDGET (gtk_builder_get_object (data->builder, "destination_name_entry"));
+ data->destination_name_fcbutton = GTK_WIDGET (gtk_builder_get_object (data->builder, "destination_folder_fcbutton"));
+ data->copying_progressbar = GTK_WIDGET (gtk_builder_get_object (data->builder, "copying_progressbar"));
+ data->copying_label = GTK_WIDGET (gtk_builder_get_object (data->builder, "copying_label"));
+
+ create_disk_image_populate (data);
+
+ /* Make sure we attach to parent */
+ gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (window));
+ gtk_dialog_set_default_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK);
+ gtk_widget_show_all (data->dialog);
+
+ again:
+ response = gtk_dialog_run (GTK_DIALOG (data->dialog));
+ if (response != GTK_RESPONSE_OK)
+ goto out;
+
+ if (!check_overwrite (data))
+ goto again;
+
+ s = g_strdup_printf (_("Copying data from device <i>%s</i>..."),
+ udisks_block_get_preferred_device (data->block));
+ gtk_label_set_markup (GTK_LABEL (data->copying_label), s);
+ g_free (s);
+
+ /* Advance to the progress page */
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (data->notebook), 1);
+ gtk_widget_hide (data->start_copying_button);
+
+ if (!start_copying (data))
+ goto out;
+
+ gtk_dialog_run (GTK_DIALOG (data->dialog));
+ create_disk_image_data_complete (data);
+
+ out:
+ create_disk_image_data_unref (data);
+}
diff --git a/src/palimpsest/gducreatediskimagedialog.h b/src/palimpsest/gducreatediskimagedialog.h
new file mode 100644
index 0000000..b6f3b89
--- /dev/null
+++ b/src/palimpsest/gducreatediskimagedialog.h
@@ -0,0 +1,36 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GDU_CREATE_DISK_IMAGE_DIALOG_H__
+#define __GDU_CREATE_DISK_IMAGE_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include "gdutypes.h"
+
+G_BEGIN_DECLS
+
+void gdu_create_disk_image_dialog_show (GduWindow *window,
+ UDisksObject *object);
+
+G_END_DECLS
+
+#endif /* __GDU_CREATE_DISK_IMAGE_DIALOG_H__ */
diff --git a/src/palimpsest/gduwindow.c b/src/palimpsest/gduwindow.c
index d2de2b0..1a8dabf 100644
--- a/src/palimpsest/gduwindow.c
+++ b/src/palimpsest/gduwindow.c
@@ -46,6 +46,7 @@
#include "gduformatvolumedialog.h"
#include "gducreatepartitiondialog.h"
#include "gduformatdiskdialog.h"
+#include "gducreatediskimagedialog.h"
/* Keep in sync with tabs in palimpsest.ui file */
typedef enum
@@ -99,6 +100,7 @@ struct _GduWindow
GtkWidget *devtab_toolbar_deactivate_swap_button;
GtkWidget *generic_menu;
+ GtkWidget *generic_menu_item_create_disk_image;
GtkWidget *generic_menu_item_view_smart;
GtkWidget *generic_menu_item_format_disk;
GtkWidget *generic_menu_item_drive_separator;
@@ -107,6 +109,7 @@ struct _GduWindow
GtkWidget *generic_menu_item_edit_label;
GtkWidget *generic_menu_item_edit_partition;
GtkWidget *generic_menu_item_format_volume;
+ GtkWidget *generic_menu_item_create_volume_image;
GHashTable *label_connections;
};
@@ -141,16 +144,18 @@ static const struct {
{G_STRUCT_OFFSET (GduWindow, devtab_toolbar_lock_button), "devtab-action-lock"},
{G_STRUCT_OFFSET (GduWindow, devtab_toolbar_activate_swap_button), "devtab-action-activate-swap"},
{G_STRUCT_OFFSET (GduWindow, devtab_toolbar_deactivate_swap_button), "devtab-action-deactivate-swap"},
+
{G_STRUCT_OFFSET (GduWindow, generic_menu), "generic-menu"},
+ {G_STRUCT_OFFSET (GduWindow, generic_menu_item_create_disk_image), "generic-menu-item-create-disk-image"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_view_smart), "generic-menu-item-view-smart"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_format_disk), "generic-menu-item-format-disk"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_drive_separator), "generic-menu-item-drive-separator"},
-
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_configure_fstab), "generic-menu-item-configure-fstab"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_configure_crypttab), "generic-menu-item-configure-crypttab"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_edit_label), "generic-menu-item-edit-label"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_edit_partition), "generic-menu-item-edit-partition"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_format_volume), "generic-menu-item-format-volume"},
+ {G_STRUCT_OFFSET (GduWindow, generic_menu_item_create_volume_image), "generic-menu-item-create-volume-image"},
{0, NULL}
};
@@ -180,13 +185,15 @@ typedef enum
SHOW_FLAGS_ENCRYPTED_UNLOCK_BUTTON = (1<<8),
SHOW_FLAGS_ENCRYPTED_LOCK_BUTTON = (1<<9),
- SHOW_FLAGS_POPUP_MENU_VIEW_SMART = (1<<20),
- SHOW_FLAGS_POPUP_MENU_FORMAT_DISK = (1<<21),
- SHOW_FLAGS_POPUP_MENU_CONFIGURE_FSTAB = (1<<22),
- SHOW_FLAGS_POPUP_MENU_CONFIGURE_CRYPTTAB = (1<<23),
- SHOW_FLAGS_POPUP_MENU_EDIT_LABEL = (1<<24),
- SHOW_FLAGS_POPUP_MENU_EDIT_PARTITION = (1<<25),
- SHOW_FLAGS_POPUP_MENU_FORMAT_VOLUME = (1<<26),
+ SHOW_FLAGS_POPUP_MENU_CREATE_DISK_IMAGE = (1<<20),
+ SHOW_FLAGS_POPUP_MENU_VIEW_SMART = (1<<21),
+ SHOW_FLAGS_POPUP_MENU_FORMAT_DISK = (1<<22),
+ SHOW_FLAGS_POPUP_MENU_CONFIGURE_FSTAB = (1<<23),
+ SHOW_FLAGS_POPUP_MENU_CONFIGURE_CRYPTTAB = (1<<24),
+ SHOW_FLAGS_POPUP_MENU_EDIT_LABEL = (1<<25),
+ SHOW_FLAGS_POPUP_MENU_EDIT_PARTITION = (1<<26),
+ SHOW_FLAGS_POPUP_MENU_FORMAT_VOLUME = (1<<27),
+ SHOW_FLAGS_POPUP_MENU_CREATE_VOLUME_IMAGE = (1<<28),
} ShowFlags;
static void setup_device_page (GduWindow *window, UDisksObject *object);
@@ -221,6 +228,10 @@ static void on_generic_menu_item_format_volume (GtkMenuItem *menu_item,
gpointer user_data);
static void on_generic_menu_item_format_disk (GtkMenuItem *menu_item,
gpointer user_data);
+static void on_generic_menu_item_create_volume_image (GtkMenuItem *menu_item,
+ gpointer user_data);
+static void on_generic_menu_item_create_disk_image (GtkMenuItem *menu_item,
+ gpointer user_data);
G_DEFINE_TYPE (GduWindow, gdu_window, GTK_TYPE_WINDOW);
@@ -344,10 +355,12 @@ update_for_show_flags (GduWindow *window,
}
}
- gtk_widget_set_sensitive (GTK_WIDGET (window->generic_menu_item_view_smart),
- show_flags & SHOW_FLAGS_POPUP_MENU_VIEW_SMART);
+ gtk_widget_set_sensitive (GTK_WIDGET (window->generic_menu_item_create_disk_image),
+ show_flags & SHOW_FLAGS_POPUP_MENU_CREATE_DISK_IMAGE);
gtk_widget_set_sensitive (GTK_WIDGET (window->generic_menu_item_format_disk),
show_flags & SHOW_FLAGS_POPUP_MENU_FORMAT_DISK);
+ gtk_widget_set_sensitive (GTK_WIDGET (window->generic_menu_item_view_smart),
+ show_flags & SHOW_FLAGS_POPUP_MENU_VIEW_SMART);
gtk_widget_set_sensitive (GTK_WIDGET (window->generic_menu_item_configure_fstab),
show_flags & SHOW_FLAGS_POPUP_MENU_CONFIGURE_FSTAB);
gtk_widget_set_sensitive (GTK_WIDGET (window->generic_menu_item_configure_crypttab),
@@ -358,6 +371,8 @@ update_for_show_flags (GduWindow *window,
show_flags & SHOW_FLAGS_POPUP_MENU_EDIT_PARTITION);
gtk_widget_set_sensitive (GTK_WIDGET (window->generic_menu_item_format_volume),
show_flags & SHOW_FLAGS_POPUP_MENU_FORMAT_VOLUME);
+ gtk_widget_set_sensitive (GTK_WIDGET (window->generic_menu_item_create_volume_image),
+ show_flags & SHOW_FLAGS_POPUP_MENU_CREATE_VOLUME_IMAGE);
/* TODO: don't show the button bringing up the popup menu if it has no items */
}
@@ -1028,6 +1043,14 @@ gdu_window_constructed (GObject *object)
"activate",
G_CALLBACK (on_generic_menu_item_format_volume),
window);
+ g_signal_connect (window->generic_menu_item_create_disk_image,
+ "activate",
+ G_CALLBACK (on_generic_menu_item_create_disk_image),
+ window);
+ g_signal_connect (window->generic_menu_item_create_volume_image,
+ "activate",
+ G_CALLBACK (on_generic_menu_item_create_volume_image),
+ window);
g_idle_add (on_constructed_in_idle, g_object_ref (window));
}
@@ -1821,11 +1844,17 @@ update_device_page_for_block (GduWindow *window,
filesystem = udisks_object_peek_filesystem (object);
/* TODO: don't show on CD-ROM drives etc. */
- if (udisks_block_get_size (block) > 0 && !read_only)
+ if (udisks_block_get_size (block) > 0)
{
+ *show_flags |= SHOW_FLAGS_POPUP_MENU_CREATE_VOLUME_IMAGE;
if (udisks_block_get_hint_partitionable (block))
- *show_flags |= SHOW_FLAGS_POPUP_MENU_FORMAT_DISK;
- *show_flags |= SHOW_FLAGS_POPUP_MENU_FORMAT_VOLUME;
+ *show_flags |= SHOW_FLAGS_POPUP_MENU_CREATE_DISK_IMAGE;
+ if (!read_only)
+ {
+ if (udisks_block_get_hint_partitionable (block))
+ *show_flags |= SHOW_FLAGS_POPUP_MENU_FORMAT_DISK;
+ *show_flags |= SHOW_FLAGS_POPUP_MENU_FORMAT_VOLUME;
+ }
}
if (partition != NULL && !read_only)
@@ -2317,6 +2346,34 @@ on_generic_menu_item_format_volume (GtkMenuItem *menu_item,
/* ---------------------------------------------------------------------------------------------------- */
static void
+on_generic_menu_item_create_disk_image (GtkMenuItem *menu_item,
+ gpointer user_data)
+{
+ GduWindow *window = GDU_WINDOW (user_data);
+ UDisksObject *object;
+
+ object = gdu_volume_grid_get_block_object (GDU_VOLUME_GRID (window->volume_grid));
+ g_assert (object != NULL);
+ gdu_create_disk_image_dialog_show (window, object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_generic_menu_item_create_volume_image (GtkMenuItem *menu_item,
+ gpointer user_data)
+{
+ GduWindow *window = GDU_WINDOW (user_data);
+ UDisksObject *object;
+
+ object = gdu_volume_grid_get_selected_device (GDU_VOLUME_GRID (window->volume_grid));
+ g_assert (object != NULL);
+ gdu_create_disk_image_dialog_show (window, object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
on_generic_menu_item_format_disk (GtkMenuItem *menu_item,
gpointer user_data)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]