From 88a461a889592430250fa89e2999c1cc15e47cb8 Mon Sep 17 00:00:00 2001 From: Ting-Wei Lan Date: Sat, 27 Jul 2013 22:41:25 +0800 Subject: Add seek and skip callback functions for libarchive Seek callback function is required to extract 7-zip file. --- autoarchive/autoar-extract.c | 140 +++++++++++++++++++++++++++++++++---- autoarchive/test-extract.c | 5 +- lib/widgets/ephy-download-widget.c | 1 - 3 files changed, 126 insertions(+), 20 deletions(-) diff --git a/autoarchive/autoar-extract.c b/autoarchive/autoar-extract.c index f869f16d8..9be8df7e2 100644 --- a/autoarchive/autoar-extract.c +++ b/autoarchive/autoar-extract.c @@ -268,6 +268,8 @@ autoar_extract_dispose (GObject *object) AutoarExtract *arextract; arextract = AUTOAR_EXTRACT (object); + g_debug ("AutoarExtract: dispose"); + g_clear_object (&(arextract->priv->arpref)); G_OBJECT_CLASS (autoar_extract_parent_class)->dispose (object); @@ -282,6 +284,8 @@ autoar_extract_finalize (GObject *object) arextract = AUTOAR_EXTRACT (object); priv = arextract->priv; + g_debug ("AutoarExtract: finalize"); + g_free (priv->source); priv->source = NULL; @@ -381,6 +385,76 @@ libarchive_read_read_cb (struct archive *ar_read, return read_size; } +static off_t +libarchive_read_seek_cb (struct archive *ar_read, + void *client_data, + off_t request, + int whence) +{ + AutoarExtract *arextract; + GSeekable *seekable; + GSeekType seektype; + off_t new_offset; + + g_debug ("libarchive_read_seek_cb: called"); + + arextract = (AutoarExtract*)client_data; + seekable = (GSeekable*)(arextract->priv->istream); + if (arextract->priv->error != NULL) { + return -1; + } + + switch (whence) { + case SEEK_SET: + seektype = G_SEEK_SET; + break; + case SEEK_CUR: + seektype = G_SEEK_CUR; + break; + case SEEK_END: + seektype = G_SEEK_END; + break; + default: + return -1; + } + + g_seekable_seek (seekable, + request, + seektype, + NULL, + &(arextract->priv->error)); + new_offset = g_seekable_tell (seekable); + g_return_val_if_fail (arextract->priv->error == NULL, -1); + + g_debug ("libarchive_read_seek_cb: %"G_GOFFSET_FORMAT, (goffset)new_offset); + return new_offset; +} + +static off_t +libarchive_read_skip_cb (struct archive *ar_read, + void *client_data, + off_t request) +{ + AutoarExtract *arextract; + GSeekable *seekable; + off_t old_offset, new_offset; + + g_debug ("libarchive_read_skip_cb: called"); + + arextract = (AutoarExtract*)client_data; + seekable = (GSeekable*)(arextract->priv->istream); + if (arextract->priv->error != NULL) { + return -1; + } + + old_offset = g_seekable_tell (seekable); + new_offset = libarchive_read_seek_cb (ar_read, client_data, request, SEEK_CUR); + if (new_offset > old_offset) + return (new_offset - old_offset); + + return 0; +} + static char* _g_filename_basename_remove_extension (const char *filename) { @@ -1017,11 +1091,13 @@ autoar_extract_run (AutoarExtract *arextract, a = archive_read_new (); archive_read_support_filter_all (a); archive_read_support_format_all (a); - r = archive_read_open (a, - arextract, - libarchive_read_open_cb, - libarchive_read_read_cb, - libarchive_read_close_cb); + archive_read_set_open_callback (a, libarchive_read_open_cb); + archive_read_set_read_callback (a, libarchive_read_read_cb); + archive_read_set_close_callback (a, libarchive_read_close_cb); + archive_read_set_seek_callback (a, libarchive_read_seek_cb); + archive_read_set_skip_callback (a, libarchive_read_skip_cb); + archive_read_set_callback_data (a, arextract); + r = archive_read_open1 (a); if (r != ARCHIVE_OK) { if (arextract->priv->error == NULL) { arextract->priv->error = g_error_new (autoar_extract_quark, @@ -1076,14 +1152,30 @@ autoar_extract_run (AutoarExtract *arextract, arextract->priv->size += archive_entry_size (entry); archive_read_data_skip (a); } + if (r != ARCHIVE_EOF) { + if (arextract->priv->error == NULL) { + arextract->priv->error = g_error_new (autoar_extract_quark, + archive_errno (a), + "\'%s\': %s", + arextract->priv->source, + archive_error_string (a)); + } + _g_signal_emit (in_thread, arextract, autoar_extract_signals[ERROR], 0, arextract->priv->error); + g_free (pathname_prefix); + g_ptr_array_unref (pattern_compiled); + g_hash_table_unref (bad_filename); + archive_read_close (a); + archive_read_free (a); + return; + } + g_free (pathname_prefix); + g_ptr_array_unref (pattern_compiled); archive_read_close (a); archive_read_free (a); - g_ptr_array_unref (pattern_compiled); if (arextract->priv->error != NULL) { _g_signal_emit (in_thread, arextract, autoar_extract_signals[ERROR], 0, arextract->priv->error); g_hash_table_unref (bad_filename); - archive_read_free (a); return; } g_debug ("autoar_extract_run: has_top_level_dir = %s", @@ -1100,7 +1192,7 @@ autoar_extract_run (AutoarExtract *arextract, top_level_dir = g_file_get_child (top_level_parent_dir, top_level_dir_basename); top_level_dir_basename_modified = NULL; - for (i=1; g_file_query_exists (top_level_dir, NULL); i++) { + for (i = 1; g_file_query_exists (top_level_dir, NULL); i++) { g_free (top_level_dir_basename_modified); g_object_unref (top_level_dir); top_level_dir_basename_modified = g_strdup_printf ("%s (%d)", @@ -1132,12 +1224,13 @@ autoar_extract_run (AutoarExtract *arextract, a = archive_read_new (); archive_read_support_filter_all (a); archive_read_support_format_all (a); - - r = archive_read_open (a, - arextract, - libarchive_read_open_cb, - libarchive_read_read_cb, - libarchive_read_close_cb); + archive_read_set_open_callback (a, libarchive_read_open_cb); + archive_read_set_read_callback (a, libarchive_read_read_cb); + archive_read_set_close_callback (a, libarchive_read_close_cb); + archive_read_set_seek_callback (a, libarchive_read_seek_cb); + archive_read_set_skip_callback (a, libarchive_read_skip_cb); + archive_read_set_callback_data (a, arextract); + r = archive_read_open1 (a); if (r != ARCHIVE_OK) { if (arextract->priv->error == NULL) { arextract->priv->error = g_error_new (autoar_extract_quark, @@ -1154,7 +1247,7 @@ autoar_extract_run (AutoarExtract *arextract, } userhash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); grouphash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - while (archive_read_next_header (a, &entry) == ARCHIVE_OK) { + while ((r = archive_read_next_header (a, &entry)) == ARCHIVE_OK) { const char *pathname; const char *pathname_skip_prefix; char **pathname_chunks; @@ -1224,6 +1317,23 @@ autoar_extract_run (AutoarExtract *arextract, ((double)(arextract->priv->completed_files)) / ((double)(arextract->priv->files))); g_object_unref (extracted_filename); } + if (r != ARCHIVE_EOF) { + if (arextract->priv->error == NULL) { + arextract->priv->error = g_error_new (autoar_extract_quark, + archive_errno (a), + "\'%s\': %s", + arextract->priv->source, + archive_error_string (a)); + } + _g_signal_emit (in_thread, arextract, autoar_extract_signals[ERROR], 0, arextract->priv->error); + g_object_unref (top_level_dir); + g_hash_table_unref (userhash); + g_hash_table_unref (grouphash); + g_hash_table_unref (bad_filename); + archive_read_close (a); + archive_read_free (a); + return; + } g_object_unref (top_level_dir); g_hash_table_unref (userhash); diff --git a/autoarchive/test-extract.c b/autoarchive/test-extract.c index bf5f6cac5..b6721fc04 100644 --- a/autoarchive/test-extract.c +++ b/autoarchive/test-extract.c @@ -41,9 +41,7 @@ my_handler_error (AutoarExtract *arextract, GError *error, gpointer data) { - g_printerr ("\nError: %s\n", error->message); - g_error_free (error); - exit (1); + g_printerr ("\nError %d: %s\n", error->code, error->message); } static void @@ -51,7 +49,6 @@ my_handler_completed (AutoarExtract *arextract, gpointer data) { g_print ("\nCompleted!\n"); - exit (0); } int diff --git a/lib/widgets/ephy-download-widget.c b/lib/widgets/ephy-download-widget.c index 3ce554809..498ac3eec 100644 --- a/lib/widgets/ephy-download-widget.c +++ b/lib/widgets/ephy-download-widget.c @@ -412,7 +412,6 @@ widget_archive_error_cb (AutoarExtract *arextract, update_download_label_and_tooltip (widget, errmsg); update_download_icon (widget); g_free (dest); - g_error_free (error); } static void -- cgit v1.2.3