summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTing-Wei Lan <lantw44@gmail.com>2013-07-15 22:46:17 +0800
committerLAN-TW <lantw44@gmail.com>2013-07-15 22:46:17 +0800
commit2cbeb6b022c134b69d5cfb0d3a6cb7c065a57a5e (patch)
tree2843e2f7ee728217001791599fadd50e6906e124
parent865bf9143320af01e6d9cbebfc6eba1b25da04ae (diff)
downloadgsoc2013-libgnome-autoar-2cbeb6b022c134b69d5cfb0d3a6cb7c065a57a5e.tar
gsoc2013-libgnome-autoar-2cbeb6b022c134b69d5cfb0d3a6cb7c065a57a5e.tar.gz
gsoc2013-libgnome-autoar-2cbeb6b022c134b69d5cfb0d3a6cb7c065a57a5e.tar.bz2
gsoc2013-libgnome-autoar-2cbeb6b022c134b69d5cfb0d3a6cb7c065a57a5e.tar.lz
gsoc2013-libgnome-autoar-2cbeb6b022c134b69d5cfb0d3a6cb7c065a57a5e.tar.xz
gsoc2013-libgnome-autoar-2cbeb6b022c134b69d5cfb0d3a6cb7c065a57a5e.tar.zst
gsoc2013-libgnome-autoar-2cbeb6b022c134b69d5cfb0d3a6cb7c065a57a5e.zip
Add functions to writing files and a new testing program
Several mistakes are discovered and fixed using the testing program.
-rw-r--r--Makefile.am30
-rw-r--r--autoar-extract.c506
-rw-r--r--autoar-extract.h7
-rw-r--r--test-extract.c77
4 files changed, 448 insertions, 172 deletions
diff --git a/Makefile.am b/Makefile.am
index 2dbe3d5..3404336 100644
--- a/Makefile.am
+++ b/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/autoar-extract.c b/autoar-extract.c
index 1dce790..8972f94 100644
--- a/autoar-extract.c
+++ b/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/autoar-extract.h b/autoar-extract.h
index 66bdbd3..524658c 100644
--- a/autoar-extract.h
+++ b/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/test-extract.c b/test-extract.c
new file mode 100644
index 0000000..58e1332
--- /dev/null
+++ b/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;
+}