aboutsummaryrefslogtreecommitdiffstats
path: root/autoarchive/autoar-extract.c
diff options
context:
space:
mode:
Diffstat (limited to 'autoarchive/autoar-extract.c')
-rw-r--r--autoarchive/autoar-extract.c1373
1 files changed, 0 insertions, 1373 deletions
diff --git a/autoarchive/autoar-extract.c b/autoarchive/autoar-extract.c
deleted file mode 100644
index e7c4c7e61..000000000
--- a/autoarchive/autoar-extract.c
+++ /dev/null
@@ -1,1373 +0,0 @@
-/* vim: set sw=2 ts=2 sts=2 et: */
-/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/*
- * autoar-extract.c
- * Automatically extract archives in some GNOME programs
- *
- * Copyright (C) 2013 Ting-Wei Lan
- *
- * This program 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 program 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 program; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-
-#include "autoar-extract.h"
-
-#include "autoar-common.h"
-#include "autoar-pref.h"
-
-#include <archive.h>
-#include <archive_entry.h>
-#include <gio/gio.h>
-#include <gobject/gvaluecollector.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#if defined HAVE_MKFIFO || defined HAVE_MKNOD
-# include <fcntl.h>
-#endif
-
-#ifdef HAVE_GETPWNAM
-# include <pwd.h>
-#endif
-
-#ifdef HAVE_GETGRNAM
-# include <grp.h>
-#endif
-
-
-G_DEFINE_TYPE (AutoarExtract, autoar_extract, G_TYPE_OBJECT)
-
-#define AUTOAR_EXTRACT_GET_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), AUTOAR_TYPE_EXTRACT, AutoarExtractPrivate))
-
-#define BUFFER_SIZE (64 * 1024)
-#define NOT_AN_ARCHIVE_ERRNO 2013
-
-struct _AutoarExtractPrivate
-{
- char *source;
- char *output;
-
- guint64 size;
- guint64 completed_size;
-
- guint files;
- guint completed_files;
-
- AutoarPref *arpref;
-
- GInputStream *istream;
- void *buffer;
- gssize buffer_size;
- GError *error;
-};
-
-enum
-{
- SCANNED,
- DECIDE_DEST,
- PROGRESS,
- COMPLETED,
- ERROR,
- LAST_SIGNAL
-};
-
-enum
-{
- PROP_0,
- PROP_SOURCE,
- PROP_OUTPUT,
- PROP_SIZE,
- PROP_COMPLETED_SIZE,
- PROP_FILES,
- 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,
- GValue *value,
- GParamSpec *pspec)
-{
- AutoarExtract *arextract;
- AutoarExtractPrivate *priv;
-
- arextract = AUTOAR_EXTRACT (object);
- priv = arextract->priv;
-
- switch (property_id) {
- case PROP_SOURCE:
- g_value_set_string (value, priv->source);
- break;
- case PROP_OUTPUT:
- g_value_set_string (value, priv->output);
- break;
- case PROP_SIZE:
- g_value_set_uint64 (value, priv->size);
- break;
- case PROP_COMPLETED_SIZE:
- g_value_set_uint64 (value, priv->completed_size);
- break;
- case PROP_FILES:
- g_value_set_uint (value, priv->files);
- break;
- case PROP_COMPLETED_FILES:
- g_value_set_uint (value, priv->completed_files);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-static void
-autoar_extract_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- AutoarExtract *arextract;
- AutoarExtractPrivate *priv;
-
- arextract = AUTOAR_EXTRACT (object);
- priv = arextract->priv;
-
- switch (property_id) {
- case PROP_SIZE:
- autoar_extract_set_size (arextract, g_value_get_uint64 (value));
- break;
- case PROP_COMPLETED_SIZE:
- autoar_extract_set_completed_size (arextract, g_value_get_uint64 (value));
- break;
- case PROP_FILES:
- autoar_extract_set_files (arextract, g_value_get_uint (value));
- break;
- case PROP_COMPLETED_FILES:
- autoar_extract_set_completed_files (arextract, g_value_get_uint (value));
- break;
- case PROP_SOURCE:
- g_free (priv->source);
- priv->source = g_value_dup_string (value);
- break;
- case PROP_OUTPUT:
- g_free (priv->output);
- priv->output = g_value_dup_string (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-char*
-autoar_extract_get_source (AutoarExtract *arextract)
-{
- g_return_val_if_fail (AUTOAR_IS_EXTRACT (arextract), NULL);
- return arextract->priv->source;
-}
-
-char*
-autoar_extract_get_output (AutoarExtract *arextract)
-{
- g_return_val_if_fail (AUTOAR_IS_EXTRACT (arextract), NULL);
- return arextract->priv->output;
-}
-
-guint64
-autoar_extract_get_size (AutoarExtract *arextract)
-{
- g_return_val_if_fail (AUTOAR_IS_EXTRACT (arextract), 0);
- return arextract->priv->size;
-}
-
-guint64
-autoar_extract_get_completed_size (AutoarExtract *arextract)
-{
- g_return_val_if_fail (AUTOAR_IS_EXTRACT (arextract), 0);
- return arextract->priv->completed_size;
-}
-
-guint
-autoar_extract_get_files (AutoarExtract *arextract)
-{
- g_return_val_if_fail (AUTOAR_IS_EXTRACT (arextract), 0);
- return arextract->priv->files;
-}
-
-guint
-autoar_extract_get_completed_files (AutoarExtract *arextract)
-{
- g_return_val_if_fail (AUTOAR_IS_EXTRACT (arextract), 0);
- return arextract->priv->completed_files;
-}
-
-void
-autoar_extract_set_size (AutoarExtract *arextract,
- guint64 size)
-{
- g_return_if_fail (AUTOAR_IS_EXTRACT (arextract));
- arextract->priv->size = size;
-}
-
-void
-autoar_extract_set_completed_size (AutoarExtract *arextract,
- guint64 completed_size)
-{
- g_return_if_fail (AUTOAR_IS_EXTRACT (arextract));
- g_return_if_fail (completed_size <= arextract->priv->completed_size);
- arextract->priv->completed_size = completed_size;
-}
-
-void
-autoar_extract_set_files (AutoarExtract *arextract,
- guint files)
-{
- g_return_if_fail (AUTOAR_IS_EXTRACT (arextract));
- arextract->priv->files = files;
-}
-
-void
-autoar_extract_set_completed_files (AutoarExtract *arextract,
- guint completed_files)
-{
- g_return_if_fail (AUTOAR_IS_EXTRACT (arextract));
- g_return_if_fail (completed_files <= arextract->priv->completed_files);
- arextract->priv->completed_files = completed_files;
-}
-
-static void
-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);
-}
-
-static void
-autoar_extract_finalize (GObject *object)
-{
- AutoarExtract *arextract;
- AutoarExtractPrivate *priv;
-
- arextract = AUTOAR_EXTRACT (object);
- priv = arextract->priv;
-
- g_debug ("AutoarExtract: finalize");
-
- g_free (priv->source);
- priv->source = NULL;
-
- g_free (priv->output);
- priv->output = NULL;
-
- if (priv->istream != NULL) {
- if (!g_input_stream_is_closed (priv->istream)) {
- g_input_stream_close (priv->istream, NULL, NULL);
- }
- g_object_unref (priv->istream);
- }
-
- g_free (priv->buffer);
- priv->buffer = NULL;
-
- if (priv->error != NULL) {
- g_error_free (priv->error);
- priv->error = NULL;
- }
-
- G_OBJECT_CLASS (autoar_extract_parent_class)->finalize (object);
-}
-
-static int
-libarchive_read_open_cb (struct archive *ar_read,
- void *client_data)
-{
- AutoarExtract *arextract;
- GFile *file;
-
- g_debug ("libarchive_read_open_cb: called");
-
- arextract = (AutoarExtract*)client_data;
- if (arextract->priv->error != NULL) {
- return ARCHIVE_FATAL;
- }
-
- file = g_file_new_for_commandline_arg (arextract->priv->source);
-
- arextract->priv->istream = (GInputStream*)g_file_read (file,
- NULL,
- &(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;
-}
-
-static int
-libarchive_read_close_cb (struct archive *ar_read,
- void *client_data)
-{
- AutoarExtract *arextract;
-
- g_debug ("libarchive_read_close_cb: called");
-
- arextract = (AutoarExtract*)client_data;
- if (arextract->priv->error != NULL) {
- return ARCHIVE_FATAL;
- }
-
- if (arextract->priv->istream != NULL) {
- g_input_stream_close (arextract->priv->istream, NULL, NULL);
- g_object_unref (arextract->priv->istream);
- arextract->priv->istream = NULL;
- }
-
- g_debug ("libarchive_read_close_cb: ARCHIVE_OK");
- return ARCHIVE_OK;
-}
-
-static ssize_t
-libarchive_read_read_cb (struct archive *ar_read,
- void *client_data,
- const void **buffer)
-{
- 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;
- read_size = g_input_stream_read (arextract->priv->istream,
- arextract->priv->buffer,
- arextract->priv->buffer_size,
- NULL,
- &(arextract->priv->error));
- g_return_val_if_fail (arextract->priv->error == NULL, -1);
-
- g_debug ("libarchive_read_read_cb: %lu", read_size);
- 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 void
-g_pattern_spec_free_safe (void *pattern_compiled)
-{
- if (pattern_compiled != NULL)
- g_pattern_spec_free (pattern_compiled);
-}
-
-static gboolean
-autoar_extract_do_pattern_check (const char *path,
- GPtrArray *pattern)
-{
- char **path_components;
- GArray *path_components_len;
-
- int i, j, len;
-
- path_components = g_strsplit (path, "/", G_MAXINT);
- path_components_len = g_array_new (FALSE, FALSE, sizeof(size_t));
- for (i = 0; path_components[i] != NULL; i++) {
- len = strlen (path_components[i]);
- g_array_append_val (path_components_len, len);
- }
-
- for (i = 0; g_ptr_array_index (pattern, i) != NULL; i++) {
- for (j = 0; path_components[j] != NULL; j++) {
- if (g_pattern_match (g_ptr_array_index (pattern, i),
- g_array_index (path_components_len, size_t, j),
- path_components[j],
- NULL)) {
- g_debug ("autoar_extract_do_pattern_check: ### %s", path_components[j]);
- g_strfreev (path_components);
- g_array_unref (path_components_len);
- return FALSE;
- }
- }
- }
-
- g_strfreev (path_components);
- g_array_unref (path_components_len);
-
- return TRUE;
-}
-
-static void
-autoar_extract_do_write_entry (AutoarExtract *arextract,
- struct archive *a,
- struct archive_entry *entry,
- GFile *dest,
- GHashTable *userhash,
- GHashTable *grouphash,
- gboolean in_thread,
- gboolean use_raw_format)
-{
- GOutputStream *ostream;
- GFileInfo *info;
- GFile *parent;
- mode_t filetype;
- const void *buffer;
- size_t size, written;
- off_t offset;
- int r;
-
-#ifdef HAVE_GETPWNAM
- const char *uname;
-#endif
-
-#ifdef HAVE_GETGRNAM
- const char *gname;
-#endif
-
- guint32 uid, gid;
-
- 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);
- }
-
- /* user */
- g_debug ("autoar_extract_do_write_entry: user");
-#ifdef HAVE_GETPWNAM
- if ((uname = archive_entry_uname (entry)) != NULL) {
- void *got_uid;
- if (g_hash_table_lookup_extended (userhash, uname, NULL, &got_uid) == TRUE) {
- uid = GPOINTER_TO_UINT (got_uid);
- } else {
- struct passwd *pwd = getpwnam (uname);
- if (pwd == NULL) {
- uid = archive_entry_uid (entry);
- } else {
- uid = pwd->pw_uid;
- g_hash_table_insert (userhash, g_strdup (uname), GUINT_TO_POINTER (uid));
- }
- }
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID, uid);
- } else
-#endif
- if ((uid = archive_entry_uid (entry)) != 0) {
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID, uid);
- }
-
- /* group */
- g_debug ("autoar_extract_do_write_entry: group");
-#ifdef HAVE_GETGRNAM
- if ((gname = archive_entry_gname (entry)) != NULL) {
- void *got_gid;
- if (g_hash_table_lookup_extended (grouphash, gname, NULL, &got_gid) == TRUE) {
- gid = GPOINTER_TO_UINT (got_gid);
- } else {
- struct group *grp = getgrnam (gname);
- if (grp == NULL) {
- gid = archive_entry_gid (entry);
- } else {
- gid = grp->gr_gid;
- g_hash_table_insert (grouphash, g_strdup (gname), GUINT_TO_POINTER (gid));
- }
- }
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID, gid);
- } else
-#endif
- if ((gid = archive_entry_gid (entry)) != 0) {
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID, gid);
- }
-
- /* 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");
- r = 0;
- 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) {
- /* Archive entry size may be zero if we use raw format. */
- if (archive_entry_size(entry) > 0 || use_raw_format) {
- while (archive_read_data_block (a, &buffer, &size, &offset) == ARCHIVE_OK) {
- /* buffer == NULL occurs in some zip archives when an entry is
- * completely read. We just skip this situation to prevent GIO
- * warnings. */
- if (buffer == NULL)
- continue;
- 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;
- }
- arextract->priv->completed_size += written;
- autoar_common_g_signal_emit (in_thread,
- 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_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);
- }
- }
-#endif
-
- g_debug ("autoar_extract_do_write_entry: applying info");
- g_file_set_attributes_from_info (dest,
- info,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL,
- &(arextract->priv->error));
-
- if (arextract->priv->error != NULL) {
- g_debug ("autoar_extract_do_write_entry: %s\n", arextract->priv->error->message);
- g_error_free (arextract->priv->error);
- arextract->priv->error = NULL;
- }
-
- g_object_unref (info);
-}
-
-static void
-autoar_extract_class_init (AutoarExtractClass *klass)
-{
- GObjectClass *object_class;
- GType type;
-
- object_class = G_OBJECT_CLASS (klass);
- type = G_TYPE_FROM_CLASS (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->dispose = autoar_extract_dispose;
- object_class->finalize = autoar_extract_finalize;
-
- g_object_class_install_property (object_class, PROP_SOURCE,
- g_param_spec_string ("source",
- "Source archive",
- "The archive file to be extracted",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_NICK |
- G_PARAM_STATIC_BLURB));
-
- g_object_class_install_property (object_class, PROP_OUTPUT,
- g_param_spec_string ("output",
- "Output directory",
- "Output directory of extracted archive",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_NICK |
- G_PARAM_STATIC_BLURB));
-
- g_object_class_install_property (object_class, PROP_SIZE,
- g_param_spec_uint64 ("size",
- "File size",
- "Size of the extracted files",
- 0, G_MAXUINT64, 0,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_NICK |
- G_PARAM_STATIC_BLURB));
-
- g_object_class_install_property (object_class, PROP_COMPLETED_SIZE,
- g_param_spec_uint64 ("completed-size",
- "Written file size",
- "Bytes written to disk",
- 0, G_MAXUINT64, 0,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_NICK |
- G_PARAM_STATIC_BLURB));
-
- g_object_class_install_property (object_class, PROP_FILES,
- g_param_spec_uint ("files",
- "Files",
- "Number of files in the archive",
- 0, G_MAXUINT32, 0,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_NICK |
- G_PARAM_STATIC_BLURB));
-
- g_object_class_install_property (object_class, PROP_COMPLETED_FILES,
- g_param_spec_uint ("completed-files",
- "Written files",
- "Number of files has been written",
- 0, G_MAXUINT32, 0,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_NICK |
- G_PARAM_STATIC_BLURB));
-
- 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
-autoar_extract_init (AutoarExtract *arextract)
-{
- AutoarExtractPrivate *priv;
-
- priv = AUTOAR_EXTRACT_GET_PRIVATE (arextract);
- arextract->priv = priv;
-
- priv->source = NULL;
- priv->output = NULL;
-
- priv->size = 0;
- priv->completed_size = 0;
-
- priv->files = 0;
- priv->completed_files = 0;
-
- priv->arpref = NULL;
-
- priv->istream = NULL;
- priv->buffer_size = BUFFER_SIZE;
- priv->buffer = g_new (char, priv->buffer_size);
- priv->error = NULL;
-}
-
-AutoarExtract*
-autoar_extract_new (const char *source,
- const char *output,
- AutoarPref *arpref)
-{
- AutoarExtract* arextract;
-
- g_return_val_if_fail (source != NULL, NULL);
- g_return_val_if_fail (output != NULL, NULL);
-
- arextract = g_object_new (AUTOAR_TYPE_EXTRACT,
- "source", source,
- "output", output,
- NULL);
- arextract->priv->arpref = g_object_ref (arpref);
-
- return arextract;
-}
-
-static void
-autoar_extract_run (AutoarExtract *arextract,
- gboolean in_thread)
-{
- struct archive *a;
- struct archive_entry *entry;
-
- char *pathname_basename;
- char *pathname_extension;
- char *pathname_prefix;
- int pathname_prefix_len;
-
- gboolean has_top_level_dir;
- gboolean has_only_one_file;
- gboolean use_raw_format;
- char *top_level_dir_basename;
- char *top_level_dir_basename_modified;
- GFile *top_level_parent_dir;
- GFile *top_level_dir;
-
- GHashTable *userhash;
- GHashTable *grouphash;
- GHashTable *bad_filename;
-
- const char **pattern;
- GPtrArray *pattern_compiled;
-
- GFile *source;
- char *source_basename;
-
- int i, r;
-
- g_return_if_fail (AUTOAR_IS_EXTRACT (arextract));
- g_return_if_fail (arextract->priv->source != NULL);
- g_return_if_fail (arextract->priv->output != NULL);
-
- a = archive_read_new ();
- archive_read_support_filter_all (a);
- archive_read_support_format_all (a);
-
- /* Reset all counter variables */
- arextract->priv->size = 0;
- arextract->priv->completed_size = 0;
- arextract->priv->files = 0;
- arextract->priv->completed_files = 0;
-
- pattern = autoar_pref_get_pattern_to_ignore (arextract->priv->arpref);
- pattern_compiled = g_ptr_array_new_with_free_func (g_pattern_spec_free_safe);
- if (pattern != NULL) {
- for (i = 0; pattern[i] != NULL; i++)
- g_ptr_array_add (pattern_compiled, g_pattern_spec_new (pattern[i]));
- }
- g_ptr_array_add (pattern_compiled, NULL);
-
- pathname_prefix = NULL;
- pathname_prefix_len = 0;
- has_top_level_dir = TRUE;
- has_only_one_file = TRUE;
- use_raw_format = FALSE;
-
- /* Step 1: Scan all file names in the archive
- * 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. */
- g_debug ("autoar_extract_run: Step 1, Scan");
- a = archive_read_new ();
- archive_read_support_filter_all (a);
- archive_read_support_format_all (a);
- 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) {
- archive_read_free (a);
- a = archive_read_new ();
- archive_read_support_filter_all (a);
- archive_read_support_format_raw (a);
- 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 || archive_filter_count (a) <= 1) {
- if (arextract->priv->error == NULL) {
- if (r != ARCHIVE_OK) {
- arextract->priv->error = g_error_new (autoar_extract_quark,
- archive_errno (a),
- "\'%s\': %s",
- arextract->priv->source,
- archive_error_string (a));
- } else {
- /* If we only use raw format and filter count is one, libarchive will
- * not do anything except for just copying the source file. We do not
- * want this thing to happen because it does unnecesssary copying. */
- arextract->priv->error = g_error_new (autoar_extract_quark,
- NOT_AN_ARCHIVE_ERRNO,
- "\'%s\': %s",
- arextract->priv->source,
- "not an archive");
- }
- }
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[ERROR],
- 0, arextract->priv->error);
- archive_read_free (a);
- g_ptr_array_unref (pattern_compiled);
- return;
- }
- use_raw_format = TRUE;
- }
- bad_filename = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- while ((r = archive_read_next_header (a, &entry)) == ARCHIVE_OK) {
- const char *pathname, *dir_sep_location;
- size_t skip_len, prefix_len;
-
- pathname = archive_entry_pathname (entry);
- g_debug ("autoar_extract_run: %d: pathname = %s",
- arextract->priv->files,
- pathname);
-
- if (!use_raw_format && !autoar_extract_do_pattern_check (pathname, pattern_compiled)) {
- g_hash_table_insert (bad_filename, g_strdup (pathname), GUINT_TO_POINTER (TRUE));
- continue;
- }
-
- g_debug ("autoar_extract_run: %d: pattern check passed",
- arextract->priv->files);
-
- if (pathname_prefix == NULL) {
- pathname_basename = g_path_get_basename (pathname);
- skip_len = strspn (pathname, "./");
- dir_sep_location = strchr (pathname + skip_len, '/');
- if (dir_sep_location == NULL) {
- prefix_len = strlen (pathname);
- } else {
- prefix_len = dir_sep_location - pathname;
- }
- pathname_prefix = g_strndup (pathname, prefix_len);
- pathname_prefix_len = prefix_len;
- g_debug ("autoar_extract_run: pathname_prefix = %s", pathname_prefix);
- } else {
- has_only_one_file = FALSE;
- if (!g_str_has_prefix (pathname, pathname_prefix)) {
- has_top_level_dir = FALSE;
- }
- }
- arextract->priv->files++;
- 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));
- }
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[ERROR],
- 0, arextract->priv->error);
- g_free (pathname_prefix);
- g_free (pathname_basename);
- 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);
- if (arextract->priv->error != NULL) {
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[ERROR],
- 0, arextract->priv->error);
- g_hash_table_unref (bad_filename);
- return;
- }
- g_debug ("autoar_extract_run: has_top_level_dir = %s",
- has_top_level_dir ? "TRUE" : "FALSE");
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[SCANNED],
- 0, arextract->priv->files);
-
- /* Step 2: Create necessary directories
- * If the archive contains only one file, we don't create the directory */
- g_debug ("autoar_extract_run: Step 2, Mkdir-p");
- source = g_file_new_for_commandline_arg (arextract->priv->source);
- source_basename = g_file_get_basename (source);
- g_object_unref (source);
- top_level_dir_basename = autoar_common_get_basename_remove_extension (source_basename);
- 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);
-
- pathname_extension = autoar_common_get_filename_extension (pathname_basename);
- if (has_only_one_file && (pathname_extension != pathname_basename)) {
- /* If we only have one file, we have to add the file extension.
- * Although we use the variable `top_level_dir', it may be a regular
- * file, so the extension is important. */
- char *new_filename;
- new_filename = g_strconcat (top_level_dir_basename, pathname_extension, NULL);
- top_level_dir = g_file_get_child (top_level_parent_dir, new_filename);
- g_free (new_filename);
- } else {
- top_level_dir = g_file_get_child (top_level_parent_dir, top_level_dir_basename);
- pathname_extension = "";
- }
-
- top_level_dir_basename_modified = NULL;
- 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);
- if (has_only_one_file) {
- top_level_dir_basename_modified = g_strdup_printf ("%s(%d)%s",
- top_level_dir_basename,
- i,
- pathname_extension);
- } else {
- top_level_dir_basename_modified = g_strdup_printf ("%s(%d)",
- top_level_dir_basename,
- i);
- }
- top_level_dir = g_file_get_child (top_level_parent_dir,
- top_level_dir_basename_modified);
- }
-
- if (!has_only_one_file)
- g_file_make_directory_with_parents (top_level_dir, NULL, &(arextract->priv->error));
-
- g_free (pathname_basename);
- g_free (top_level_dir_basename);
- g_free (top_level_dir_basename_modified);
- g_object_unref (top_level_parent_dir);
-
- if (arextract->priv->error != NULL) {
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[ERROR],
- 0, arextract->priv->error);
- g_object_unref (top_level_dir);
- g_hash_table_unref (bad_filename);
- archive_read_free (a);
- return;
- }
-
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[DECIDE_DEST],
- 0, top_level_dir);
-
- /* Step 3: Extract files
- * We have to re-open the archive to extract files */
- g_debug ("autoar_extract_run: Step 3, Extract");
- a = archive_read_new ();
- archive_read_support_filter_all (a);
- if (use_raw_format)
- archive_read_support_format_raw (a);
- else
- archive_read_support_format_all (a);
- 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,
- archive_errno (a),
- "\'%s\': %s",
- arextract->priv->source,
- archive_error_string (a));
- }
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[ERROR],
- 0, arextract->priv->error);
- g_object_unref (top_level_dir);
- g_hash_table_unref (bad_filename);
- archive_read_free (a);
- return;
- }
- 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 ((r = archive_read_next_header (a, &entry)) == ARCHIVE_OK) {
- const char *pathname;
- const char *pathname_skip_prefix;
- char **pathname_chunks;
-
- GFile *extracted_filename;
-
- pathname = archive_entry_pathname (entry);
- if (GPOINTER_TO_UINT (g_hash_table_lookup (bad_filename, pathname)))
- continue;
-
- if (!has_only_one_file) {
- if (has_top_level_dir)
- pathname_skip_prefix = pathname + pathname_prefix_len;
- 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. */
- if (!g_file_has_prefix (extracted_filename, top_level_dir)) {
- pathname_chunks = g_strsplit (pathname_skip_prefix, "/", G_MAXINT);
- for (i = 0; pathname_chunks[i] != NULL; i++) {
- if (strcmp (pathname_chunks[i], "..") == 0) {
- char *pathname_sanitized;
-
- *pathname_chunks[i] = '\0';
- pathname_sanitized = g_strjoinv ("/", pathname_chunks);
-
- g_object_unref (extracted_filename);
- extracted_filename = g_file_get_child (top_level_dir, pathname_sanitized);
-
- g_free (pathname_sanitized);
-
- if (g_file_has_prefix (extracted_filename, top_level_dir))
- break;
- }
- }
- g_strfreev (pathname_chunks);
- }
- } else {
- extracted_filename = g_object_ref (top_level_dir);
- }
-
- autoar_extract_do_write_entry (arextract,
- a,
- entry,
- extracted_filename,
- userhash,
- grouphash,
- in_thread,
- use_raw_format);
-
- if (arextract->priv->error != NULL) {
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[ERROR],
- 0, arextract->priv->error);
- g_object_unref (extracted_filename);
- 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;
- }
-
- arextract->priv->completed_files++;
- autoar_common_g_signal_emit (in_thread,
- 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);
- }
- 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));
- }
- autoar_common_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);
- g_hash_table_unref (grouphash);
- g_hash_table_unref (bad_filename);
- archive_read_close (a);
- archive_read_free (a);
- if (arextract->priv->error != NULL) {
- autoar_common_g_signal_emit (in_thread, 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. */
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[PROGRESS],
- 0, 1.0, 1.0);
- g_debug ("autoar_extract_run: Finalize");
- if (autoar_pref_get_delete_if_succeed (arextract->priv->arpref)) {
- g_debug ("autoar_extract_run: Delete");
- source = g_file_new_for_commandline_arg (arextract->priv->source);
- g_file_delete (source, NULL, NULL);
- g_object_unref (source);
- }
- autoar_common_g_signal_emit (in_thread, arextract,
- autoar_extract_signals[COMPLETED], 0);
-}
-
-void
-autoar_extract_start (AutoarExtract *arextract)
-{
- autoar_extract_run (arextract, FALSE);
-}
-
-static void
-autoar_extract_start_async_thread (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- AutoarExtract *arextract = source_object;
- autoar_extract_run (arextract, TRUE);
- g_task_return_pointer (task, NULL, g_free);
- g_object_unref (arextract);
-}
-
-
-void
-autoar_extract_start_async (AutoarExtract *arextract)
-{
- GTask *task;
-
- g_object_ref (arextract);
-
- task = g_task_new (arextract, NULL, NULL, NULL);
- g_task_set_task_data (task, NULL, NULL);
- g_task_run_in_thread (task, autoar_extract_start_async_thread);
-}