diff options
Diffstat (limited to 'autoarchive')
-rw-r--r-- | autoarchive/Makefile.am | 30 | ||||
-rw-r--r-- | autoarchive/autoar-extract.c | 506 | ||||
-rw-r--r-- | autoarchive/autoar-extract.h | 7 | ||||
-rw-r--r-- | autoarchive/test-extract.c | 77 |
4 files changed, 448 insertions, 172 deletions
diff --git a/autoarchive/Makefile.am b/autoarchive/Makefile.am index 2dbe3d553..3404336bb 100644 --- a/autoarchive/Makefile.am +++ b/autoarchive/Makefile.am @@ -1,23 +1,39 @@ -NULL = +# vim: set sw=8 ts=8 sts=8 noet: -noinst_LTLIBRARIES = libautoarchive.la +NULL = +noinst_PROGRAMS = +EXTRA_DIST = NOINST_H_FILES = \ autoar-extract.h \ $(NULL) - INST_H_FILES = \ $(NULL) +noinst_LTLIBRARIES = libautoarchive.la libautoarchive_la_SOURCES = \ autoar-extract.c \ $(INST_H_FILES) \ $(NOINST_H_FILES) \ $(NULL) - libautoarchive_la_CPPFLAGS = \ - $(AM_CPPFLAGS) - + $(AM_CPPFLAGS) \ + $(NULL) libautoarchive_la_CFLAGS = \ $(DEPENDENCIES_CFLAGS) \ - $(AM_CFLAGS) + $(AM_CFLAGS) \ + $(NULL) + +noinst_PROGRAMS += test-extract +EXTRA_DIST += test-extract.c +test_extract_SOURCES = \ + test-extract.c \ + $(NULL) +test_extract_CFLAGS = \ + $(DEPENDENCIES_CFLAGS) \ + $(AM_CFLAGS) \ + $(NULL) +test_extract_LDADD = \ + $(DEPENDENCIES_LIBS) \ + libautoarchive.la \ + $(NULL) diff --git a/autoarchive/autoar-extract.c b/autoarchive/autoar-extract.c index 1dce79008..8972f946b 100644 --- a/autoarchive/autoar-extract.c +++ b/autoarchive/autoar-extract.c @@ -29,8 +29,12 @@ #include <archive.h> #include <archive_entry.h> +#include <fcntl.h> #include <gio/gio.h> #include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> G_DEFINE_TYPE (AutoarExtract, autoar_extract, G_TYPE_OBJECT) @@ -58,6 +62,16 @@ struct _AutoarExtractPrivate enum { + SCANNED, + DECIDE_DEST, + PROGRESS, + COMPLETED, + ERROR, + LAST_SIGNAL +}; + +enum +{ PROP_0, PROP_SOURCE, PROP_OUTPUT, @@ -67,6 +81,9 @@ enum PROP_COMPLETED_FILES }; +static guint autoar_extract_signals[LAST_SIGNAL] = { 0 }; +static GQuark autoar_extract_quark; + static void autoar_extract_get_property (GObject *object, guint property_id, @@ -260,6 +277,8 @@ libarchive_read_open_cb (struct archive *ar_read, GFile *file; GFileInfo *fileinfo; + g_debug ("libarchive_read_open_cb: called"); + arextract = (AutoarExtract*)client_data; if (arextract->priv->error != NULL) { return ARCHIVE_FATAL; @@ -282,6 +301,7 @@ libarchive_read_open_cb (struct archive *ar_read, &(arextract->priv->error)); g_return_val_if_fail (arextract->priv->error == NULL, ARCHIVE_FATAL); + g_debug ("libarchive_read_open_cb: ARCHIVE_OK"); return ARCHIVE_OK; } @@ -291,6 +311,8 @@ libarchive_read_close_cb (struct archive *ar_read, { AutoarExtract *arextract; + g_debug ("libarchive_read_close_cb: called"); + arextract = (AutoarExtract*)client_data; if (arextract->priv->error != NULL) { return ARCHIVE_FATAL; @@ -302,6 +324,7 @@ libarchive_read_close_cb (struct archive *ar_read, arextract->priv->istream = NULL; } + g_debug ("libarchive_read_close_cb: ARCHIVE_OK"); return ARCHIVE_OK; } @@ -313,12 +336,14 @@ libarchive_read_read_cb (struct archive *ar_read, AutoarExtract *arextract; gssize read_size; + g_debug ("libarchive_read_read_cb: called"); + arextract = (AutoarExtract*)client_data; if (arextract->priv->error != NULL) { return -1; } - *buffer = &(arextract->priv->buffer); + *buffer = arextract->priv->buffer; read_size = g_input_stream_read (arextract->priv->istream, arextract->priv->buffer, arextract->priv->buffer_size, @@ -328,6 +353,7 @@ libarchive_read_read_cb (struct archive *ar_read, arextract->priv->completed_size += read_size; + g_debug ("libarchive_read_read_cb: %lu", read_size); return read_size; } @@ -346,133 +372,204 @@ _g_filename_basename_remove_extension (const char *filename) dot_location = strrchr (basename, '.'); if (dot_location == NULL || dot_location == basename) { + g_debug ("_g_filename_basename_remove_extension: %s => %s, nothing is removed", + filename, + basename); return basename; } if (dot_location - 4 > basename) { - if (strcmp (dot_location - 4, ".tar") == 0) { + if (strncmp (dot_location - 4, ".tar", 4) == 0) { dot_location -= 4; } } *dot_location = '\0'; + g_debug ("_g_filename_basename_remove_extension: %s => %s", + filename, + basename); return basename; } static gboolean -archive_extract_do_pattern_check (const char *pathname) +autoar_extract_do_pattern_check (const char *pathname) { return TRUE; } static void -archive_extract_do_write_entry (AutoarExtract *arextract, +autoar_extract_do_write_entry (AutoarExtract *arextract, struct archive *a, struct archive_entry *entry, GFile *dest) { -} + GOutputStream *ostream; + GFileInfo *info; + GFile *parent; + mode_t filetype; + const void *buffer; + size_t size, written; + off_t offset; + int r; + + parent = g_file_get_parent (dest); + if (!g_file_query_exists (parent, NULL)) + g_file_make_directory_with_parents (parent, NULL, NULL); + g_object_unref (parent); + + info = g_file_info_new (); + + /* time */ + g_debug ("autoar_extract_do_write_entry: time"); + if (archive_entry_atime_is_set (entry)) { + g_file_info_set_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_ACCESS, + archive_entry_atime (entry)); + g_file_info_set_attribute_uint32 (info, + G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, + archive_entry_atime_nsec (entry) / 1000); + } + if (archive_entry_birthtime_is_set (entry)) { + g_file_info_set_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_CREATED, + archive_entry_birthtime (entry)); + g_file_info_set_attribute_uint32 (info, + G_FILE_ATTRIBUTE_TIME_CREATED_USEC, + archive_entry_birthtime_nsec (entry) / 1000); + } + if (archive_entry_ctime_is_set (entry)) { + g_file_info_set_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_CHANGED, + archive_entry_ctime (entry)); + g_file_info_set_attribute_uint32 (info, + G_FILE_ATTRIBUTE_TIME_CHANGED_USEC, + archive_entry_ctime_nsec (entry) / 1000); + } + if (archive_entry_mtime_is_set (entry)) { + g_file_info_set_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_MODIFIED, + archive_entry_mtime (entry)); + g_file_info_set_attribute_uint32 (info, + G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, + archive_entry_mtime_nsec (entry) / 1000); + } -/* Additional marshaller generated by glib-genmarshal - * Command: echo "VOID:DOUBLE,DOUBLE" | glib-genmarshal --header */ - -/* VOID:DOUBLE,DOUBLE (/dev/stdin:1) */ -extern void g_cclosure_user_marshal_VOID__DOUBLE_DOUBLE (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); - -/* Additional marshaller generated by glib-genmarshal - * Command: echo "VOID:DOUBLE,DOUBLE" | glib-genmarshal --body */ - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* VOID:DOUBLE,DOUBLE (/dev/stdin:1) */ -void -g_cclosure_user_marshal_VOID__DOUBLE_DOUBLE (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE) (gpointer data1, - gdouble arg_1, - gdouble arg_2, - gpointer data2); - register GMarshalFunc_VOID__DOUBLE_DOUBLE callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; + /* permissions */ + g_debug ("autoar_extract_do_write_entry: permissions"); + g_file_info_set_attribute_uint32 (info, + G_FILE_ATTRIBUTE_UNIX_MODE, + archive_entry_mode (entry)); + + + + + + g_debug ("autoar_extract_do_write_entry: writing"); + switch (filetype = archive_entry_filetype (entry)) { + case AE_IFREG: + ostream = (GOutputStream*)g_file_replace (dest, + NULL, + FALSE, + G_FILE_CREATE_NONE, + NULL, + &(arextract->priv->error)); + if (arextract->priv->error != NULL) { + g_object_unref (info); + return; + } + if (ostream != NULL) { + if (archive_entry_size(entry) > 0) { + while (archive_read_data_block (a, &buffer, &size, &offset) == ARCHIVE_OK) { + g_output_stream_write_all (ostream, + buffer, + size, + &written, + NULL, + &(arextract->priv->error)); + if (arextract->priv->error != NULL) { + g_output_stream_close (ostream, NULL, NULL); + g_object_unref (ostream); + g_object_unref (info); + return; + } + } + } + g_output_stream_close (ostream, NULL, NULL); + g_object_unref (ostream); + } + break; + case AE_IFDIR: + g_file_make_directory_with_parents (dest, NULL, &(arextract->priv->error)); + if (arextract->priv->error != NULL) { + /* "File exists" is not a fatal error */ + if (arextract->priv->error->code == G_IO_ERROR_EXISTS) { + g_error_free (arextract->priv->error); + arextract->priv->error = NULL; + } + } + break; + case AE_IFLNK: + g_file_make_symbolic_link (dest, + archive_entry_symlink (entry), + NULL, + &(arextract->priv->error)); + break; + /* FIFOs, sockets, block files, character files are not important + * in the regular archives, so errors are not fatal. */ +#if defined HAVE_MKFIFO || defined HAVE_MKNOD + case AE_IFIFO: +# ifdef HAVE_MKFIFO + r = mkfifo (g_file_get_path (dest), archive_entry_mode (entry)); +# else + r = mknod (g_file_get_path (dest), + S_IFIFO | archive_entry_mode (entry), + 0); +# endif + break; +#endif +#ifdef HAVE_MKNOD + case AE_IFSOCK: + r = mknod (g_file_get_path (dest), + S_IFSOCK | archive_entry_mode (entry), + 0); + break; + case AE_IFBLK: + r = mknod (g_file_get_path (dest), + S_IFBLK | archive_entry_mode (entry), + archive_entry_rdev (entry)); + break; + case AE_IFCHR: + r = mknod (g_file_get_path (dest), + S_IFCHR | archive_entry_mode (entry), + archive_entry_rdev (entry)); + break; +#endif + } + +#if defined HAVE_MKFIFO || defined HAVE_MKNOD + /* Create a empty regular file if we cannot create the special file. */ + if (r < 0 && (filetype == AE_IFIFO || + filetype == AE_IFSOCK || + filetype == AE_IFBLK || + filetype == AE_IFCHR)) { + ostream = (GOutputStream*)g_file_append_to (dest, G_FILE_CREATE_NONE, NULL, NULL); + if (ostream != NULL) { + g_output_stream_close (ostream, NULL, NULL); + g_object_unref (ostream); } - callback = (GMarshalFunc_VOID__DOUBLE_DOUBLE) (marshal_data ? marshal_data : cc->callback); + } +#endif - callback (data1, - g_marshal_value_peek_double (param_values + 1), - g_marshal_value_peek_double (param_values + 2), - data2); + g_debug ("autoar_extract_do_write_entry: applying info"); + g_file_set_attributes_from_info (dest, + info, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, + NULL); + g_object_unref (info); } - static void autoar_extract_class_init (AutoarExtractClass *klass) { @@ -484,6 +581,8 @@ autoar_extract_class_init (AutoarExtractClass *klass) g_type_class_add_private (klass, sizeof (AutoarExtractPrivate)); + autoar_extract_quark = g_quark_from_static_string ("autoar-extract"); + object_class->get_property = autoar_extract_get_property; object_class->set_property = autoar_extract_set_property; object_class->finalize = autoar_extract_finalize; @@ -493,7 +592,7 @@ autoar_extract_class_init (AutoarExtractClass *klass) "Source archive", "The archive file to be extracted", NULL, - G_PARAM_READABLE | + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | @@ -504,7 +603,7 @@ autoar_extract_class_init (AutoarExtractClass *klass) "Output directory", "Output directory of extracted archive", NULL, - G_PARAM_READABLE | + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | @@ -540,44 +639,60 @@ autoar_extract_class_init (AutoarExtractClass *klass) G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); - g_signal_new ("scaned", - type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AutoarExtractClass, scaned), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - 1, - G_TYPE_UINT); - - g_signal_new ("progress", - type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AutoarExtractClass, progress), - NULL, NULL, - g_cclosure_user_marshal_VOID__DOUBLE_DOUBLE, - G_TYPE_NONE, - 2, - G_TYPE_DOUBLE, - G_TYPE_DOUBLE); - - g_signal_new ("completed", - type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AutoarExtractClass, completed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_signal_new ("error", - type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AutoarExtractClass, error), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); + autoar_extract_signals[SCANNED] = + g_signal_new ("scanned", + type, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (AutoarExtractClass, scanned), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, + 1, + G_TYPE_UINT); + + autoar_extract_signals[DECIDE_DEST] = + g_signal_new ("decide-dest", + type, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (AutoarExtractClass, decide_dest), + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 1, + G_TYPE_FILE); + + autoar_extract_signals[PROGRESS] = + g_signal_new ("progress", + type, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (AutoarExtractClass, progress), + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 2, + G_TYPE_DOUBLE, + G_TYPE_DOUBLE); + + autoar_extract_signals[COMPLETED] = + g_signal_new ("completed", + type, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (AutoarExtractClass, completed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + autoar_extract_signals[ERROR] = + g_signal_new ("error", + type, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (AutoarExtractClass, error), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); } static void @@ -635,7 +750,7 @@ autoar_extract_start (AutoarExtract* arextract) GFile *source; - int i; + int i, r; g_return_if_fail (AUTOAR_IS_EXTRACT (arextract)); g_return_if_fail (arextract->priv->source != NULL); @@ -655,11 +770,27 @@ autoar_extract_start (AutoarExtract* arextract) * We have to check whether the archive contains a top-level directory * before performing the extraction. We emit the "scanned" signal when * the checking is completed. */ - archive_read_open (a, - arextract, - libarchive_read_open_cb, - libarchive_read_read_cb, - libarchive_read_close_cb); + g_debug ("autoar_extract_start: Step 1, Scan"); + 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); + if (r != ARCHIVE_OK) { + if (arextract->priv->error == NULL) { + arextract->priv->error = g_error_new (autoar_extract_quark, + archive_errno (a), + "Error when opening the archive \'%s\': %s", + arextract->priv->source, + archive_error_string (a)); + } + g_signal_emit (arextract, autoar_extract_signals[ERROR], 0, arextract->priv->error); + archive_read_free (a); + return; + } pathname_prefix = NULL; has_top_level_dir = TRUE; while (archive_read_next_header (a, &entry) == ARCHIVE_OK) { @@ -667,6 +798,9 @@ autoar_extract_start (AutoarExtract* arextract) size_t skip_len, prefix_len; pathname = archive_entry_pathname (entry); + g_debug ("autoar_extract_start: %d: pathname = %s", + arextract->priv->files, + pathname); /* TODO: Add file name pattern check here */ @@ -680,6 +814,7 @@ autoar_extract_start (AutoarExtract* arextract) } pathname_prefix = g_strndup (pathname, prefix_len); pathname_prefix_len = prefix_len; + g_debug ("autoar_extract_start: pathname_prefix = %s", pathname_prefix); } else { if (!g_str_has_prefix (pathname, pathname_prefix)) { has_top_level_dir = FALSE; @@ -690,14 +825,18 @@ autoar_extract_start (AutoarExtract* arextract) } g_free (pathname_prefix); archive_read_close (a); + archive_read_free (a); if (arextract->priv->error != NULL) { - g_signal_emit_by_name (arextract, "error", arextract->priv->error); + g_signal_emit (arextract, autoar_extract_signals[ERROR], 0, arextract->priv->error); archive_read_free (a); return; } - g_signal_emit_by_name (arextract, "scanned"); + g_debug ("autoar_extract_start: has_top_level_dir = %s", + has_top_level_dir ? "TRUE" : "FALSE"); + g_signal_emit (arextract, autoar_extract_signals[SCANNED], 0, arextract->priv->files); /* Step 2: Create necessary directories */ + g_debug ("autoar_extract_start: Step 2, Mkdir-p"); top_level_dir_basename = _g_filename_basename_remove_extension (arextract->priv->source); top_level_parent_dir = g_file_new_for_commandline_arg (arextract->priv->output); top_level_dir = g_file_get_child (top_level_parent_dir, top_level_dir_basename); @@ -713,6 +852,7 @@ autoar_extract_start (AutoarExtract* arextract) top_level_dir_basename_modified); } + g_debug ("autoar_extract_start: %s", top_level_dir_basename_modified); g_file_make_directory_with_parents (top_level_dir, NULL, &(arextract->priv->error)); g_free (top_level_dir_basename); @@ -720,26 +860,49 @@ autoar_extract_start (AutoarExtract* arextract) g_object_unref (top_level_parent_dir); if (arextract->priv->error != NULL) { - g_signal_emit_by_name (arextract, "error", arextract->priv->error); + g_signal_emit (arextract, autoar_extract_signals[ERROR], 0, arextract->priv->error); g_object_unref (top_level_dir); archive_read_free (a); return; } + g_signal_emit (arextract, autoar_extract_signals[DECIDE_DEST], 0, top_level_dir); + /* Step 3: Extract files * We have to re-open the archive to extract files */ - archive_read_open (a, - arextract, - libarchive_read_open_cb, - libarchive_read_read_cb, - libarchive_read_close_cb); + g_debug ("autoar_extract_start: Step 3, Extract"); + a = archive_read_new (); + archive_read_support_filter_all (a); + archive_read_support_format_all (a); + + /* We have to reset completed_size because it have been modified in Step 1 */ + arextract->priv->completed_size = 0; + + r = archive_read_open (a, + arextract, + libarchive_read_open_cb, + libarchive_read_read_cb, + libarchive_read_close_cb); + if (r != ARCHIVE_OK) { + if (arextract->priv->error == NULL) { + arextract->priv->error = g_error_new (autoar_extract_quark, + archive_errno (a), + "Error when opening the archive \'%s\': %s", + arextract->priv->source, + archive_error_string (a)); + } + g_signal_emit (arextract, autoar_extract_signals[ERROR], 0, arextract->priv->error); + g_object_unref (top_level_dir); + archive_read_free (a); + return; + } while (archive_read_next_header (a, &entry) == ARCHIVE_OK) { const char *pathname; const char *pathname_skip_prefix; char **pathname_chunks; GFile *extracted_filename; - GFileInfo *restored_fileinfo; + char *debug_filename; pathname = archive_entry_pathname (entry); if (has_top_level_dir) @@ -747,6 +910,7 @@ autoar_extract_start (AutoarExtract* arextract) else pathname_skip_prefix = pathname + strspn (pathname, "./"); + for (; *pathname_skip_prefix == '/'; pathname_skip_prefix++); extracted_filename = g_file_get_child (top_level_dir, pathname_skip_prefix); /* Extracted file should not be located outside the top level directory. */ @@ -771,17 +935,31 @@ autoar_extract_start (AutoarExtract* arextract) g_strfreev (pathname_chunks); } + debug_filename = g_file_get_path (extracted_filename); + g_debug ("autoar_extract_start: destination = %s", debug_filename); + g_free (debug_filename); + /* TODO: Add file name pattern check here */ - archive_extract_do_pattern_check (pathname_skip_prefix); + autoar_extract_do_pattern_check (pathname_skip_prefix); /* TODO: Write entry to disk */ - archive_extract_do_write_entry (arextract, a, entry, extracted_filename); + autoar_extract_do_write_entry (arextract, a, entry, extracted_filename); + + if (arextract->priv->error != NULL) { + g_signal_emit (arextract, autoar_extract_signals[ERROR], 0, arextract->priv->error); + g_object_unref (extracted_filename); + g_object_unref (top_level_dir); + archive_read_close (a); + archive_read_free (a); + return; + } arextract->priv->completed_files++; - g_signal_emit_by_name (arextract, - "progress", - ((double)(arextract->priv->size)) / ((double)(arextract->priv->completed_size)), - ((double)(arextract->priv->files)) / ((double)(arextract->priv->completed_files))); + g_signal_emit (arextract, + autoar_extract_signals[PROGRESS], + 0, + ((double)(arextract->priv->completed_size)) / ((double)(arextract->priv->size)), + ((double)(arextract->priv->completed_files)) / ((double)(arextract->priv->files))); g_object_unref (extracted_filename); } @@ -789,14 +967,16 @@ autoar_extract_start (AutoarExtract* arextract) archive_read_close (a); archive_read_free (a); if (arextract->priv->error != NULL) { - g_signal_emit_by_name (arextract, "error", arextract->priv->error); + g_signal_emit (arextract, autoar_extract_signals[ERROR], 0, arextract->priv->error); return; } /* If the extraction is completed successfully, remove the source file. * Errors are not fatal because we have completed our work. */ + g_signal_emit (arextract, autoar_extract_signals[PROGRESS], 0, 1.0, 1.0); + g_debug ("autoar_extract_start: Finalize, Delete"); source = g_file_new_for_commandline_arg (arextract->priv->source); g_file_delete (source, NULL, NULL); g_object_unref (source); - g_signal_emit_by_name (arextract, "completed"); + g_signal_emit (arextract, autoar_extract_signals[COMPLETED], 0); } diff --git a/autoarchive/autoar-extract.h b/autoarchive/autoar-extract.h index 66bdbd367..524658cfa 100644 --- a/autoarchive/autoar-extract.h +++ b/autoarchive/autoar-extract.h @@ -27,6 +27,7 @@ #define AUTOAR_EXTRACT_H #include <glib-object.h> +#include <gio/gio.h> G_BEGIN_DECLS @@ -52,14 +53,16 @@ struct _AutoarExtractClass { GObjectClass parent_class; - void (* scaned) (AutoarExtract *arextract, + void (* scanned) (AutoarExtract *arextract, guint files); + void (* decide_dest)(AutoarExtract *arextract, + GFile *destination); void (* progress) (AutoarExtract *arextract, gdouble fraction_size, gdouble fraction_files); void (* completed) (AutoarExtract *arextract); void (* error) (AutoarExtract *arextract, - GError* error); + GError *error); }; GType autoar_extract_get_type (void) G_GNUC_CONST; diff --git a/autoarchive/test-extract.c b/autoarchive/test-extract.c new file mode 100644 index 000000000..58e133222 --- /dev/null +++ b/autoarchive/test-extract.c @@ -0,0 +1,77 @@ +/* vim: set sw=2 ts=2 sts=2 et: */ + +#include "autoar-extract.h" +#include <stdlib.h> + +static void +my_handler_scanned (AutoarExtract *arextract, + guint files, + gpointer data) +{ + g_print ("Scanning OK, %d files to be extracted.\n", files); +} + +static void +my_handler_decide_dest (AutoarExtract *arextract, + GFile *dest) +{ + char *path, *uri; + path = g_file_get_path (dest); + uri = g_file_get_uri (dest); + g_print ("Destination Path: %s\n", path); + g_print ("Destination URI: %s\n", uri); + g_free (path); + g_free (uri); +} + +static void +my_handler_progress (AutoarExtract *arextract, + gdouble fraction_size, + gdouble fraction_files, + gpointer data) +{ + g_print ("Progress: Archive Size %.2lf %%, Files %.2lf %%\n", + fraction_size * 100, + fraction_files * 100); +} + +static void +my_handler_error (AutoarExtract *arextract, + GError *error, + gpointer data) +{ + g_printerr ("Error: %s\n", error->message); + g_error_free (error); + exit (1); +} + +static void +my_handler_completed (AutoarExtract *arextract, + gpointer data) +{ + g_print ("Completed!\n"); + exit (0); +} + +int +main (int argc, + char *argv[]) +{ + AutoarExtract *arextract; + + if (argc < 3) { + g_printerr ("Usage: %s archive_file output_dir\n", argv[0]); + return 255; + } + + arextract = autoar_extract_new (argv[1], argv[2]); + g_signal_connect (arextract, "scanned", G_CALLBACK (my_handler_scanned), NULL); + g_signal_connect (arextract, "decide-dest", G_CALLBACK (my_handler_decide_dest), NULL); + g_signal_connect (arextract, "progress", G_CALLBACK (my_handler_progress), NULL); + g_signal_connect (arextract, "error", G_CALLBACK (my_handler_error), NULL); + g_signal_connect (arextract, "completed", G_CALLBACK (my_handler_completed), NULL); + + autoar_extract_start (arextract); + + return 0; +} |