[gnome-disk-utility] Add support for restoring XZ compressed disk images
- From: David Zeuthen <davidz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility] Add support for restoring XZ compressed disk images
- Date: Wed, 19 Jun 2013 07:10:38 +0000 (UTC)
commit 67c7e1ddd61f07c9bae36654ca73e309290eec39
Author: David Zeuthen <zeuthen gmail com>
Date: Thu Jun 13 12:53:49 2013 -0700
Add support for restoring XZ compressed disk images
Also include [1] MIME types for disk images, e.g. introduce
application/x-raw-disk-image
application/x-raw-disk-image-xz-compressed
Also add a new desktop file for a "Disk Image Writer" application that
associates these mime-types to the command
gnome-disks --restore-disk-image %U
to allow the end user to very easily copy a disk image to a device
from either his desktop shell or web browser. This feature is useful
for OS vendors distributing e.g. "rescue images".
[1] : Eventually these mimetypes should be part of the standard
shared-mime-info distribution from freedesktop.org, see
https://bugs.freedesktop.org/show_bug.cgi?id=64845
for these. Until that happens, we'll just ship them as part of
gnome-disk-utility.
Signed-off-by: David Zeuthen <zeuthen gmail com>
configure.ac | 6 +-
data/Makefile.am | 18 ++-
data/gdu-mimetypes.xml | 16 ++
data/gnome-disk-image-mounter.desktop.in | 4 +-
data/gnome-disk-image-writer.desktop.in | 11 ++
po/POTFILES.in | 2 +
src/disk-image-mounter/main.c | 4 +-
src/disks/Makefile.am | 3 +
src/disks/gducreatediskimagedialog.c | 4 +-
src/disks/gdurestorediskimagedialog.c | 83 ++++++++---
src/disks/gdutypes.h | 3 +
src/disks/gduwindow.c | 4 +-
src/disks/gduxzdecompressor.c | 238 ++++++++++++++++++++++++++++++
src/disks/gduxzdecompressor.h | 40 +++++
src/libgdu/gduutils.c | 14 ++-
src/libgdu/gduutils.h | 3 +-
16 files changed, 424 insertions(+), 29 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index e38fcf0..27140ec 100644
--- a/configure.ac
+++ b/configure.ac
@@ -110,6 +110,7 @@ CANBERRA_REQUIRED=0.1
LIBDVDREAD_REQUIRED=4.2.0
GSD_PLUGIN_REQUIRED=3.6
LIBNOTIFY_REQUIRED=0.7
+LIBLZMA_REQUIRED=5.1.0
PKG_CHECK_MODULES(GLIB2, [gmodule-2.0 gio-unix-2.0 >= $GLIB2_REQUIRED])
PKG_CHECK_MODULES(UDISKS2, [udisks2 >= $UDISKS2_REQUIRED])
@@ -118,8 +119,9 @@ PKG_CHECK_MODULES(LIBSECRET1, [libsecret-1 >= $LIBSECRET1_REQUIRED])
PKG_CHECK_MODULES(PWQUALITY, [pwquality >= $PWQUALITY_REQUIRED])
PKG_CHECK_MODULES(CANBERRA, [libcanberra-gtk3 >= $CANBERRA_REQUIRED])
PKG_CHECK_MODULES(LIBDVDREAD, [dvdread >= $LIBDVDREAD_REQUIRED])
-PKG_CHECK_MODULES(GSD_PLUGIN, [gnome-settings-daemon >= GSD_PLUGIN_REQUIRED])
-PKG_CHECK_MODULES(LIBNOTIFY, [libnotify >= LIBNOTIFY_REQUIRED])
+PKG_CHECK_MODULES(GSD_PLUGIN, [gnome-settings-daemon >= $GSD_PLUGIN_REQUIRED])
+PKG_CHECK_MODULES(LIBNOTIFY, [libnotify >= $LIBNOTIFY_REQUIRED])
+PKG_CHECK_MODULES(LIBLZMA, [liblzma >= $LIBLZMA_REQUIRED])
gsd_plugindir='${libdir}/gnome-settings-daemon-3.0'
AC_SUBST([gsd_plugindir])
diff --git a/data/Makefile.am b/data/Makefile.am
index 33ac654..726589e 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -2,8 +2,17 @@ NULL =
SUBDIRS = ui icons
+# TODO: Move gdu-mimetypes.xml to shared-mime-info, see https://bugs.freedesktop.org/show_bug.cgi?id=64845
+mimedir = $(datadir)/mime/packages
+mime_DATA = gdu-mimetypes.xml
+
desktopdir = $(datadir)/applications
-desktop_in_files = gnome-disks.desktop.in gnome-disk-image-mounter.desktop.in
+desktop_in_files = \
+ gnome-disks.desktop.in \
+ gnome-disk-image-mounter.desktop.in \
+ gnome-disk-image-writer.desktop.in \
+ $(NULL)
+
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
# GSettings schemas
@@ -23,7 +32,14 @@ EXTRA_DIST = \
CLEANFILES = \
$(gsettings_SCHEMAS) \
$(desktop_DATA) \
+ $(mime_DATA) \
$(NULL)
+install-data-hook:
+ update-mime-database $(datadir)/mime
+
+uninstall-hook:
+ update-mime-database $(datadir)/mime
+
clean-local :
rm -f *~
diff --git a/data/gdu-mimetypes.xml b/data/gdu-mimetypes.xml
new file mode 100644
index 0000000..b108bae
--- /dev/null
+++ b/data/gdu-mimetypes.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="application/x-raw-disk-image">
+ <comment>Raw disk image</comment>
+ <generic-icon name="application-x-cd-image"/>
+ <glob pattern="*.raw-disk-image"/>
+ <glob pattern="*.img"/>
+ </mime-type>
+ <mime-type type="application/x-raw-disk-image-xz-compressed">
+ <comment>Raw disk image (XZ-compressed)</comment>
+ <sub-class-of type="application/x-xz"/>
+ <generic-icon name="application-x-cd-image"/>
+ <glob pattern="*.raw-disk-image.xz"/>
+ <glob pattern="*.img.xz"/>
+ </mime-type>
+</mime-info>
diff --git a/data/gnome-disk-image-mounter.desktop.in b/data/gnome-disk-image-mounter.desktop.in
index 23d5b62..709ed26 100644
--- a/data/gnome-disk-image-mounter.desktop.in
+++ b/data/gnome-disk-image-mounter.desktop.in
@@ -4,8 +4,8 @@ _Name=Disk Image Mounter
_Comment=Mount Disk Images
Exec=gnome-disk-image-mounter %U
Icon=drive-removable-media
-MimeType=application/x-cd-image;
+MimeType=application/x-cd-image;application/x-raw-disk-image;
Terminal=false
StartupNotify=false
Type=Application
-NoDisplay=true
+NoDisplay=false
diff --git a/data/gnome-disk-image-writer.desktop.in b/data/gnome-disk-image-writer.desktop.in
new file mode 100644
index 0000000..3e587e4
--- /dev/null
+++ b/data/gnome-disk-image-writer.desktop.in
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Encoding=UTF-8
+_Name=Disk Image Writer
+_Comment=Write Disk Images to Devices
+Exec=gnome-disks --restore-disk-image %U
+Icon=drive-removable-media
+MimeType=application/x-cd-image;application/x-raw-disk-image;application/x-raw-disk-image-xz-compressed;
+Terminal=false
+StartupNotify=false
+Type=Application
+NoDisplay=false
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ae356a5..0332b4b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -2,6 +2,7 @@
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
data/gnome-disk-image-mounter.desktop.in
+data/gnome-disk-image-writer.desktop.in
data/gnome-disks.desktop.in
data/org.gnome.Disks.gschema.xml.in.in
data/org.gnome.settings-daemon.plugins.gdu-sd.gschema.xml.in.in
@@ -53,6 +54,7 @@ src/disks/gdurestorediskimagedialog.c
src/disks/gduunlockdialog.c
src/disks/gduvolumegrid.c
src/disks/gduwindow.c
+src/disks/gduxzdecompressor.c
src/disks/main.c
src/libgdu/gduutils.c
src/notify/gdusdmonitor.c
diff --git a/src/disk-image-mounter/main.c b/src/disk-image-mounter/main.c
index 95977c5..0eff7b1 100644
--- a/src/disk-image-mounter/main.c
+++ b/src/disk-image-mounter/main.c
@@ -83,7 +83,9 @@ do_filechooser (void)
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
_("_Mount"), GTK_RESPONSE_ACCEPT,
NULL);
- gdu_utils_configure_file_chooser_for_disk_images (GTK_FILE_CHOOSER (dialog), TRUE);
+ gdu_utils_configure_file_chooser_for_disk_images (GTK_FILE_CHOOSER (dialog),
+ TRUE, /* set_file_types */
+ FALSE); /* allow_compressed */
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
/* Add a RO check button that defaults to RO */
diff --git a/src/disks/Makefile.am b/src/disks/Makefile.am
index 0c76be9..9c91946 100644
--- a/src/disks/Makefile.am
+++ b/src/disks/Makefile.am
@@ -52,6 +52,7 @@ gnome_disks_SOURCES = \
gduerasemultipledisksdialog.h gduerasemultipledisksdialog.c \
gdudvdsupport.h gdudvdsupport.c \
gdulocaljob.h gdulocaljob.c \
+ gduxzdecompressor.h gduxzdecompressor.c \
$(enum_built_sources) \
$(NULL)
@@ -72,6 +73,7 @@ gnome_disks_CFLAGS = \
$(PWQUALITY_CFLAGS) \
$(CANBERRA_CFLAGS) \
$(LIBDVDREAD_CFLAGS) \
+ $(LIBLZMA_CFLAGS) \
$(WARN_CFLAGS) \
-lm \
$(NULL)
@@ -85,6 +87,7 @@ gnome_disks_LDADD = \
$(PWQUALITY_LIBS) \
$(CANBERRA_LIBS) \
$(LIBDVDREAD_LIBS) \
+ $(LIBLZMA_LIBS) \
$(top_builddir)/src/libgdu/libgdu.la \
$(NULL)
diff --git a/src/disks/gducreatediskimagedialog.c b/src/disks/gducreatediskimagedialog.c
index e5c36cd..dd7958b 100644
--- a/src/disks/gducreatediskimagedialog.c
+++ b/src/disks/gducreatediskimagedialog.c
@@ -284,7 +284,9 @@ create_disk_image_populate (DialogData *data)
g_time_zone_unref (tz);
g_free (now_string);
- gdu_utils_configure_file_chooser_for_disk_images (GTK_FILE_CHOOSER (data->folder_fcbutton), FALSE);
+ gdu_utils_configure_file_chooser_for_disk_images (GTK_FILE_CHOOSER (data->folder_fcbutton),
+ FALSE, /* set file types */
+ FALSE); /* allow_compressed */
/* Source label */
info = udisks_client_get_object_info (gdu_window_get_client (data->window), data->object);
diff --git a/src/disks/gdurestorediskimagedialog.c b/src/disks/gdurestorediskimagedialog.c
index 46479ae..813a84f 100644
--- a/src/disks/gdurestorediskimagedialog.c
+++ b/src/disks/gdurestorediskimagedialog.c
@@ -26,6 +26,7 @@
#include "gduestimator.h"
#include "gdulocaljob.h"
#include "gdudevicetreemodel.h"
+#include "gduxzdecompressor.h"
/* ---------------------------------------------------------------------------------------------------- */
@@ -72,8 +73,8 @@ typedef struct
GCancellable *cancellable;
GOutputStream *block_stream;
- GFileInputStream *file_input_stream;
- guint64 file_size;
+ GInputStream *input_stream;
+ guint64 input_size;
guchar *buffer;
guint64 total_bytes_read;
@@ -187,7 +188,7 @@ dialog_data_unref (DialogData *data)
g_clear_object (&data->estimator);
g_clear_object (&data->cancellable);
- g_clear_object (&data->file_input_stream);
+ g_clear_object (&data->input_stream);
g_clear_object (&data->block_stream);
g_mutex_clear (&data->copy_lock);
g_free (data);
@@ -251,24 +252,54 @@ restore_disk_image_update (DialogData *data)
if (restore_file != NULL)
{
+ gboolean is_xz_compressed = FALSE;
GFileInfo *info;
guint64 size;
gchar *s;
+
info = g_file_query_info (restore_file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
G_FILE_ATTRIBUTE_STANDARD_SIZE,
G_FILE_QUERY_INFO_NONE,
NULL,
NULL);
+ if (g_str_has_suffix (g_file_info_get_content_type (info), "-xz-compressed"))
+ is_xz_compressed = TRUE;
size = g_file_info_get_size (info);
g_object_unref (info);
- image_size_str = udisks_client_get_size_for_display (gdu_window_get_client (data->window), size,
FALSE, TRUE);
+ if (is_xz_compressed)
+ {
+ gsize uncompressed_size;
+ uncompressed_size = gdu_xz_decompressor_get_uncompressed_size (restore_file);
+ if (uncompressed_size == 0)
+ {
+ restore_error = g_strdup (_("File does not appear to be XZ compressed"));
+ size = 0;
+ }
+ else
+ {
+ s = udisks_client_get_size_for_display (gdu_window_get_client (data->window),
uncompressed_size, FALSE, TRUE);
+ /* Translators: Shown for a compressed disk image in the "Size" field.
+ * The %s is the uncompressed size as a long string, e.g. "4.2 MB (4,300,123
bytes)".
+ */
+ image_size_str = g_strdup_printf (_("%s when decompressed"), s);
+ g_free (s);
+ size = uncompressed_size;
+ }
+ }
+ else
+ {
+ image_size_str = udisks_client_get_size_for_display (gdu_window_get_client (data->window), size,
FALSE, TRUE);
+ }
if (data->block_size > 0)
{
if (size == 0)
{
- restore_error = g_strdup (_("Cannot restore image of size 0"));
+ /* if size is 0, error may be set already.. */
+ if (restore_error == NULL)
+ restore_error = g_strdup (_("Cannot restore image of size 0"));
}
else if (size < data->block_size)
{
@@ -482,7 +513,9 @@ populate_destination_combobox (DialogData *data)
static void
restore_disk_image_populate (DialogData *data)
{
- gdu_utils_configure_file_chooser_for_disk_images (GTK_FILE_CHOOSER (data->selectable_image_fcbutton),
TRUE);
+ gdu_utils_configure_file_chooser_for_disk_images (GTK_FILE_CHOOSER (data->selectable_image_fcbutton),
+ TRUE, /* set file types */
+ TRUE); /* allow_compressed */
/* Image: Show label if image is known, otherwise show a filechooser button */
if (data->disk_image_filename != NULL)
@@ -728,7 +761,7 @@ copy_thread_func (gpointer user_data)
buffer = (guchar*) (((gintptr) (buffer_unaligned + page_size)) & (~(page_size - 1)));
g_mutex_lock (&data->copy_lock);
- data->estimator = gdu_estimator_new (data->file_size);
+ data->estimator = gdu_estimator_new (data->input_size);
data->update_id = 0;
data->start_time_usec = g_get_real_time ();
g_mutex_unlock (&data->copy_lock);
@@ -737,7 +770,7 @@ copy_thread_func (gpointer user_data)
* device even if it was only partially read.
*/
num_bytes_completed = 0;
- while (num_bytes_completed < data->file_size)
+ while (num_bytes_completed < data->input_size)
{
gsize num_bytes_to_read;
gsize num_bytes_read;
@@ -745,8 +778,8 @@ copy_thread_func (gpointer user_data)
gint64 now_usec;
num_bytes_to_read = buffer_size;
- if (num_bytes_to_read + num_bytes_completed > data->file_size)
- num_bytes_to_read = data->file_size - num_bytes_completed;
+ if (num_bytes_to_read + num_bytes_completed > data->input_size)
+ num_bytes_to_read = data->input_size - num_bytes_completed;
/* Update GUI - but only every 200 ms and only if last update isn't pending */
g_mutex_lock (&data->copy_lock);
@@ -761,7 +794,7 @@ copy_thread_func (gpointer user_data)
}
g_mutex_unlock (&data->copy_lock);
- if (!g_input_stream_read_all (G_INPUT_STREAM (data->file_input_stream),
+ if (!g_input_stream_read_all (data->input_stream,
buffer,
num_bytes_to_read,
&num_bytes_read,
@@ -809,7 +842,7 @@ copy_thread_func (gpointer user_data)
data->end_time_usec = g_get_real_time ();
/* in either case, close the stream */
- if (!g_input_stream_close (G_INPUT_STREAM (data->file_input_stream),
+ if (!g_input_stream_close (G_INPUT_STREAM (data->input_stream),
NULL, /* cancellable */
&error2))
{
@@ -817,7 +850,7 @@ copy_thread_func (gpointer user_data)
error2->message, g_quark_to_string (error2->domain), error2->code);
g_clear_error (&error2);
}
- g_clear_object (&data->file_input_stream);
+ g_clear_object (&data->input_stream);
if (fd != -1 )
{
@@ -899,10 +932,8 @@ start_copying (DialogData *data)
else
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (data->selectable_image_fcbutton));
- data->file_input_stream = g_file_read (file,
- NULL,
- &error);
- if (data->file_input_stream == NULL)
+ data->input_stream = (GInputStream *) g_file_read (file, NULL, &error);
+ if (data->input_stream == NULL)
{
if (!(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED))
gdu_utils_show_error (GTK_WINDOW (data->dialog), _("Error opening file for reading"), error);
@@ -913,6 +944,7 @@ start_copying (DialogData *data)
error = NULL;
info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
G_FILE_ATTRIBUTE_STANDARD_SIZE,
G_FILE_QUERY_INFO_NONE,
NULL,
@@ -924,7 +956,22 @@ start_copying (DialogData *data)
dialog_data_complete_and_unref (data);
goto out;
}
- data->file_size = g_file_info_get_size (info);
+ data->input_size = g_file_info_get_size (info);
+ if (g_str_has_suffix (g_file_info_get_content_type (info), "-xz-compressed"))
+ {
+ GduXzDecompressor *decompressor;
+ GInputStream *decompressed_input_stream;
+
+ data->input_size = gdu_xz_decompressor_get_uncompressed_size (file);
+
+ decompressor = gdu_xz_decompressor_new ();
+ decompressed_input_stream = g_converter_input_stream_new (G_INPUT_STREAM (data->input_stream),
+ G_CONVERTER (decompressor));
+ g_clear_object (&decompressor);
+
+ g_object_unref (data->input_stream);
+ data->input_stream = decompressed_input_stream;
+ }
g_object_unref (info);
data->inhibit_cookie = gtk_application_inhibit (GTK_APPLICATION (gdu_window_get_application
(data->window)),
diff --git a/src/disks/gdutypes.h b/src/disks/gdutypes.h
index 887cc71..50145e9 100644
--- a/src/disks/gdutypes.h
+++ b/src/disks/gdutypes.h
@@ -46,6 +46,9 @@ typedef struct GduDVDSupport GduDVDSupport;
struct GduLocalJob;
typedef struct GduLocalJob GduLocalJob;
+struct GduXzDecompressor;
+typedef struct GduXzDecompressor GduXzDecompressor;
+
G_END_DECLS
#endif /* __GDU_TYPES_H__ */
diff --git a/src/disks/gduwindow.c b/src/disks/gduwindow.c
index e5218ff..a7fc766 100644
--- a/src/disks/gduwindow.c
+++ b/src/disks/gduwindow.c
@@ -873,7 +873,9 @@ gdu_window_show_attach_disk_image (GduWindow *window)
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
_("_Attach"), GTK_RESPONSE_ACCEPT,
NULL);
- gdu_utils_configure_file_chooser_for_disk_images (GTK_FILE_CHOOSER (dialog), TRUE);
+ gdu_utils_configure_file_chooser_for_disk_images (GTK_FILE_CHOOSER (dialog),
+ TRUE, /* set file types */
+ FALSE); /* allow_compressed */
/* Add a RO check button that defaults to RO */
ro_checkbutton = gtk_check_button_new_with_mnemonic (_("Set up _read-only loop device"));
diff --git a/src/disks/gduxzdecompressor.c b/src/disks/gduxzdecompressor.c
new file mode 100644
index 0000000..b20fe9f
--- /dev/null
+++ b/src/disks/gduxzdecompressor.c
@@ -0,0 +1,238 @@
+/* XZ Decompressor - based on GLib's GZLibDecompressor
+ *
+ * Copyright (C) 2013 David Zeuthen
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * Licensed under GPL version 2 or later.
+ *
+ * Author: David Zeuthen <zeuthen gmail com>
+ * Alexander Larsson <alexl redhat com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "gduxzdecompressor.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <lzma.h>
+
+static void gdu_xz_decompressor_iface_init (GConverterIface *iface);
+
+struct GduXzDecompressor
+{
+ GObject parent_instance;
+
+ lzma_stream stream;
+};
+
+G_DEFINE_TYPE_WITH_CODE (GduXzDecompressor, gdu_xz_decompressor, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
+ gdu_xz_decompressor_iface_init))
+
+static void
+gdu_xz_decompressor_finalize (GObject *object)
+{
+ GduXzDecompressor *decompressor = GDU_XZ_DECOMPRESSOR (object);
+
+ lzma_end (&decompressor->stream);
+
+ G_OBJECT_CLASS (gdu_xz_decompressor_parent_class)->finalize (object);
+}
+
+static void
+init_lzma (GduXzDecompressor *decompressor)
+{
+ lzma_ret ret;
+ memset (&decompressor->stream, 0, sizeof decompressor->stream);
+ ret = lzma_stream_decoder (&decompressor->stream,
+ UINT64_MAX, /* memlimit */
+ 0); /* flags */
+ if (ret != LZMA_OK)
+ g_critical ("Error initalizing lzma decoder: %d", ret);
+}
+
+static void
+gdu_xz_decompressor_init (GduXzDecompressor *decompressor)
+{
+ init_lzma (decompressor);
+}
+
+static void
+gdu_xz_decompressor_class_init (GduXzDecompressorClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = gdu_xz_decompressor_finalize;
+}
+
+GduXzDecompressor *
+gdu_xz_decompressor_new (void)
+{
+ GduXzDecompressor *decompressor;
+
+ decompressor = g_object_new (GDU_TYPE_XZ_DECOMPRESSOR,
+ NULL);
+
+ return decompressor;
+}
+
+static void
+gdu_xz_decompressor_reset (GConverter *converter)
+{
+ GduXzDecompressor *decompressor = GDU_XZ_DECOMPRESSOR (converter);
+ lzma_end (&decompressor->stream);
+ init_lzma (decompressor);
+}
+
+static GConverterResult
+gdu_xz_decompressor_convert (GConverter *converter,
+ const void *inbuf,
+ gsize inbuf_size,
+ void *outbuf,
+ gsize outbuf_size,
+ GConverterFlags flags,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error)
+{
+ GduXzDecompressor *decompressor = GDU_XZ_DECOMPRESSOR (converter);
+ lzma_ret res;
+
+ decompressor->stream.next_in = (void *)inbuf;
+ decompressor->stream.avail_in = inbuf_size;
+
+ decompressor->stream.next_out = outbuf;
+ decompressor->stream.avail_out = outbuf_size;
+
+ res = lzma_code (&decompressor->stream, LZMA_RUN);
+
+ if (res == LZMA_DATA_ERROR)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+ _("Invalid compressed data"));
+ return G_CONVERTER_ERROR;
+ }
+
+ if (res == LZMA_MEM_ERROR)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Not enough memory"));
+ return G_CONVERTER_ERROR;
+ }
+
+ if (res == LZMA_FORMAT_ERROR)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Internal error"));
+ return G_CONVERTER_ERROR;
+ }
+
+ if (res == LZMA_BUF_ERROR)
+ {
+ if (flags & G_CONVERTER_FLUSH)
+ return G_CONVERTER_FLUSHED;
+
+ /* LZMA_FINISH not set, so this means no progress could be made
+ * We do have output space, so this should only happen if we
+ * have no input but need some.
+ */
+
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
+ _("Need more input"));
+ return G_CONVERTER_ERROR;
+ }
+
+ g_assert (res == LZMA_OK || res == LZMA_STREAM_END);
+
+ *bytes_read = inbuf_size - decompressor->stream.avail_in;
+ *bytes_written = outbuf_size - decompressor->stream.avail_out;
+
+ if (res == LZMA_STREAM_END)
+ return G_CONVERTER_FINISHED;
+
+ return G_CONVERTER_CONVERTED;
+}
+
+static void
+gdu_xz_decompressor_iface_init (GConverterIface *iface)
+{
+ iface->convert = gdu_xz_decompressor_convert;
+ iface->reset = gdu_xz_decompressor_reset;
+}
+
+gsize
+gdu_xz_decompressor_get_uncompressed_size (GFile *compressed_file)
+{
+ gchar *path = NULL;
+ gsize ret = 0;
+ GMappedFile *mapped_file = NULL;
+ size_t bufpos = 0;
+ uint64_t memlimit = UINT64_MAX;
+ lzma_index *index_object = NULL;
+ lzma_ret res;
+ GError *error = NULL;
+ uint8_t *buf;
+ gsize len;
+ lzma_stream_flags stream_flags;
+ uint8_t *footer, *index;
+
+ path = g_file_get_path (compressed_file);
+ if (path == NULL)
+ {
+ gchar *uri;
+ uri = g_file_get_uri (compressed_file);
+ g_warning ("No path for URI '%s'. Maybe you need to enable FUSE.", uri);
+ g_free (uri);
+ goto out;
+ }
+
+ mapped_file = g_mapped_file_new (path, FALSE /* writable */, &error);
+ if (mapped_file == NULL)
+ {
+ g_warning ("Error mapping file '%s': %s",
+ path, error->message);
+ g_clear_error (&error);
+ goto out;
+ }
+
+ buf = (uint8_t*) g_mapped_file_get_contents (mapped_file);
+ len = g_mapped_file_get_length (mapped_file);
+
+ if (len < 12)
+ goto out;
+ footer = buf + len - 12;
+ if (lzma_stream_footer_decode (&stream_flags, footer) != LZMA_OK)
+ goto out;
+ if (stream_flags.backward_size > len - 12)
+ goto out;
+ index = footer - stream_flags.backward_size;
+
+ res = lzma_index_buffer_decode (&index_object,
+ &memlimit,
+ NULL /* allocator */,
+ index,
+ &bufpos,
+ footer - index);
+ if (res != LZMA_OK)
+ goto out;
+
+ ret = lzma_index_uncompressed_size (index_object);
+
+ out:
+ if (index_object != NULL)
+ lzma_index_end (index_object, NULL);
+ if (mapped_file != NULL)
+ g_mapped_file_unref (mapped_file);
+ g_free (path);
+ return ret;
+}
diff --git a/src/disks/gduxzdecompressor.h b/src/disks/gduxzdecompressor.h
new file mode 100644
index 0000000..bedb34b
--- /dev/null
+++ b/src/disks/gduxzdecompressor.h
@@ -0,0 +1,40 @@
+/* XZ Decompressor - based on GLib's GZLibDecompressor
+ *
+ * Copyright (C) 2013 David Zeuthen
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * Licensed under GPL version 2 or later.
+ *
+ * Author: David Zeuthen <zeuthen gmail com>
+ * Alexander Larsson <alexl redhat com>
+ */
+
+#ifndef __GDU_XZ_DECOMPRESSOR_H__
+#define __GDU_XZ_DECOMPRESSOR_H__
+
+#include "gdutypes.h"
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_XZ_DECOMPRESSOR (gdu_xz_decompressor_get_type ())
+#define GDU_XZ_DECOMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_XZ_DECOMPRESSOR,
GduXzDecompressor))
+#define GDU_XZ_DECOMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDU_TYPE_XZ_DECOMPRESSOR,
GduXzDecompressorClass))
+#define GDU_IS_XZ_DECOMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_XZ_DECOMPRESSOR))
+#define GDU_IS_XZ_DECOMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_XZ_DECOMPRESSOR))
+#define GDU_XZ_DECOMPRESSOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_XZ_DECOMPRESSOR,
GduXzDecompressorClass))
+
+typedef struct GduXzDecompressorClass GduXzDecompressorClass;
+
+struct GduXzDecompressorClass
+{
+ GObjectClass parent_class;
+};
+
+GType gdu_xz_decompressor_get_type (void) G_GNUC_CONST;
+GduXzDecompressor *gdu_xz_decompressor_new (void);
+
+gsize gdu_xz_decompressor_get_uncompressed_size (GFile *compressed_file);
+
+G_END_DECLS
+
+#endif /* __GDU_XZ_DECOMPRESSOR_H__ */
diff --git a/src/libgdu/gduutils.c b/src/libgdu/gduutils.c
index ca8e097..d6d046f 100644
--- a/src/libgdu/gduutils.c
+++ b/src/libgdu/gduutils.c
@@ -65,7 +65,8 @@ gdu_utils_has_configuration (UDisksBlock *block,
void
gdu_utils_configure_file_chooser_for_disk_images (GtkFileChooser *file_chooser,
- gboolean set_file_types)
+ gboolean set_file_types,
+ gboolean allow_compressed)
{
GtkFileFilter *filter;
gchar *folder;
@@ -92,8 +93,17 @@ gdu_utils_configure_file_chooser_for_disk_images (GtkFileChooser *file_chooser,
gtk_file_filter_add_pattern (filter, "*");
gtk_file_chooser_add_filter (file_chooser, filter); /* adopts filter */
filter = gtk_file_filter_new ();
- gtk_file_filter_set_name (filter, _("Disk Images (*.img, *.iso)"));
+ if (allow_compressed)
+ gtk_file_filter_set_name (filter, _("Disk Images (*.img, *.img.xz, *.iso)"));
+ else
+ gtk_file_filter_set_name (filter, _("Disk Images (*.img, *.iso)"));
+ gtk_file_filter_add_pattern (filter, "*.raw-disk-image");
gtk_file_filter_add_pattern (filter, "*.img");
+ if (allow_compressed)
+ {
+ gtk_file_filter_add_pattern (filter, "*.raw-disk-image.xz");
+ gtk_file_filter_add_pattern (filter, "*.img.xz");
+ }
gtk_file_filter_add_pattern (filter, "*.iso");
gtk_file_chooser_add_filter (file_chooser, filter); /* adopts filter */
gtk_file_chooser_set_filter (file_chooser, filter);
diff --git a/src/libgdu/gduutils.h b/src/libgdu/gduutils.h
index 15822a1..c5dcacd 100644
--- a/src/libgdu/gduutils.h
+++ b/src/libgdu/gduutils.h
@@ -19,7 +19,8 @@ gboolean gdu_utils_has_configuration (UDisksBlock *block,
gboolean *out_has_passphrase);
void gdu_utils_configure_file_chooser_for_disk_images (GtkFileChooser *file_chooser,
- gboolean set_file_types);
+ gboolean set_file_types,
+ gboolean allow_compressed);
void gdu_utils_file_chooser_for_disk_images_update_settings (GtkFileChooser *file_chooser);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]