summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTing-Wei Lan <lantw44@gmail.com>2013-08-01 01:11:57 +0800
committerLAN-TW <lantw44@gmail.com>2013-08-01 01:11:57 +0800
commit7d1ac45c887b582a28ab19739993ae0a2a3e8881 (patch)
tree184934741274643e8501fdd7e1ddc2e05a3c2c48
parentd189f748e85233828478cacd1bcb4fe83f44fdcc (diff)
downloadgsoc2013-libgnome-autoar-7d1ac45c887b582a28ab19739993ae0a2a3e8881.tar
gsoc2013-libgnome-autoar-7d1ac45c887b582a28ab19739993ae0a2a3e8881.tar.gz
gsoc2013-libgnome-autoar-7d1ac45c887b582a28ab19739993ae0a2a3e8881.tar.bz2
gsoc2013-libgnome-autoar-7d1ac45c887b582a28ab19739993ae0a2a3e8881.tar.lz
gsoc2013-libgnome-autoar-7d1ac45c887b582a28ab19739993ae0a2a3e8881.tar.xz
gsoc2013-libgnome-autoar-7d1ac45c887b582a28ab19739993ae0a2a3e8881.tar.zst
gsoc2013-libgnome-autoar-7d1ac45c887b582a28ab19739993ae0a2a3e8881.zip
Add AutoarCreate reading and writing support with hard link resolving
These codes have not been tested, so it may contain serious bugs.
-rw-r--r--configure.ac2
-rw-r--r--gnome-autoar/autoar-create.c609
2 files changed, 607 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac
index e39f586..8ce97d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,7 +50,7 @@ AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
# Checks for library functions.
-AC_CHECK_FUNCS([getgrnam getpwnam link mkfifo mknod])
+AC_CHECK_FUNCS([getgrnam getpwnam link mkfifo mknod stat])
AC_CONFIG_FILES([Makefile
gnome-autoar/Makefile
diff --git a/gnome-autoar/autoar-create.c b/gnome-autoar/autoar-create.c
index 4b946bd..7846431 100644
--- a/gnome-autoar/autoar-create.c
+++ b/gnome-autoar/autoar-create.c
@@ -26,11 +26,17 @@
#include "config.h"
#include "autoar-create.h"
+#include "autoar-common.h"
#include "autoar-pref.h"
+#include <archive.h>
+#include <archive_entry.h>
#include <gio/gio.h>
#include <glib.h>
#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
G_DEFINE_TYPE (AutoarCreate, autoar_create, G_TYPE_OBJECT)
@@ -43,6 +49,7 @@ struct _AutoarCreatePrivate
{
char **source;
char *output;
+ GFile *dest;
guint64 size; /* This field is currently unused */
guint64 completed_size;
@@ -288,6 +295,342 @@ autoar_create_finalize (GObject *object)
G_OBJECT_CLASS (autoar_create_parent_class)->finalize (object);
}
+static int
+libarchive_write_open_cb (struct archive *ar_write,
+ void *client_data)
+{
+ AutoarCreate *arcreate;
+
+ g_debug ("libarchive_write_open_cb: called");
+
+ arcreate = (AutoarCreate*)client_data;
+ if (arcreate->priv->error != NULL) {
+ return ARCHIVE_FATAL;
+ }
+
+ arcreate->priv->ostream = (GOutputStream*)g_file_create (arcreate->priv->dest,
+ G_FILE_CREATE_NONE,
+ NULL,
+ &(arcreate->priv->error));
+ g_return_val_if_fail (arcreate->priv->error == NULL, ARCHIVE_FATAL);
+
+ g_debug ("libarchive_write_open_cb: ARCHIVE_OK");
+ return ARCHIVE_OK;
+}
+
+static int
+libarchive_write_close_cb (struct archive *ar_write,
+ void *client_data)
+{
+ AutoarCreate *arcreate;
+
+ g_debug ("libarchive_write_close_cb: called");
+
+ arcreate = (AutoarCreate*)client_data;
+ if (arcreate->priv->error != NULL) {
+ return ARCHIVE_FATAL;
+ }
+
+ if (arcreate->priv->ostream != NULL) {
+ g_output_stream_close (arcreate->priv->ostream, NULL, &(arcreate->priv->error));
+ g_object_unref (arcreate->priv->ostream);
+ arcreate->priv->ostream = NULL;
+ }
+
+ if (arcreate->priv->error != NULL) {
+ g_debug ("libarchive_write_close_cb: ARCHIVE_FATAL");
+ return ARCHIVE_FATAL;
+ }
+
+ g_debug ("libarchive_write_close_cb: ARCHIVE_OK");
+ return ARCHIVE_OK;
+}
+
+static ssize_t
+libarchive_write_write_cb (struct archive *ar_write,
+ void *client_data,
+ const void *buffer,
+ size_t length)
+{
+ AutoarCreate *arcreate;
+ gssize write_size;
+
+ g_debug ("libarchive_write_write_cb: called");
+
+ arcreate = (AutoarCreate*)client_data;
+ if (arcreate->priv->error != NULL) {
+ return -1;
+ }
+
+ write_size = g_output_stream_write (arcreate->priv->ostream,
+ buffer,
+ length,
+ NULL,
+ &(arcreate->priv->error));
+ g_return_val_if_fail (arcreate->priv->error == NULL, -1);
+
+ g_debug ("libarchive_write_write_cb: %lu", write_size);
+ return write_size;
+}
+
+static void
+autoar_create_do_write_data (AutoarCreate *arcreate,
+ struct archive *a,
+ struct archive_entry *entry,
+ GFile *file,
+ gboolean in_thread)
+{
+ int r;
+
+ if (arcreate->priv->error != NULL)
+ return;
+
+ while ((r = archive_write_header (a, entry)) == ARCHIVE_RETRY);
+ if (r == ARCHIVE_FATAL) {
+ if (arcreate->priv->error == NULL)
+ arcreate->priv->error = g_error_new_literal (autoar_create_quark,
+ archive_errno (a),
+ archive_error_string (a));
+ return;
+ }
+
+ if (archive_entry_size (entry) > 0) {
+ GInputStream *istream;
+ ssize_t read_actual, written_actual, written_acc;
+
+ istream = (GInputStream*)g_file_read (file, NULL, &(arcreate->priv->error));
+ if (istream == NULL)
+ return;
+
+ arcreate->priv->completed_files++;
+
+ do {
+ read_actual = g_input_stream_read (istream,
+ arcreate->priv->buffer,
+ arcreate->priv->buffer_size,
+ NULL,
+ &(arcreate->priv->error));
+ arcreate->priv->completed_size += read_actual > 0 ? read_actual : 0;
+ autoar_common_g_signal_emit (in_thread,
+ arcreate,
+ autoar_create_signals[PROGRESS],
+ 0,
+ (double)(arcreate->priv->completed_size),
+ (double)(arcreate->priv->completed_files));
+ if (read_actual > 0) {
+ written_acc = 0;
+ do {
+ written_actual = archive_write_data (a, (const char*)(arcreate->priv->buffer) + written_acc, read_actual);
+ written_acc += written_actual > 0 ? written_actual : 0;
+ } while (written_acc < read_actual && written_actual >= 0);
+ }
+ } while (read_actual > 0 && written_actual >= 0);
+
+
+ g_input_stream_close (istream, NULL, NULL);
+ g_object_unref (istream);
+
+ if (read_actual < 0)
+ return;
+
+ if (written_actual < 0) {
+ if (arcreate->priv->error == NULL)
+ arcreate->priv->error = g_error_new_literal (autoar_create_quark,
+ archive_errno (a),
+ archive_error_string (a));
+ return;
+ }
+ }
+}
+
+static void
+autoar_create_do_add_to_archive (AutoarCreate *arcreate,
+ struct archive *a,
+ struct archive_entry *entry,
+ struct archive_entry_linkresolver *resolver,
+ GFile *root,
+ GFile *file,
+ const char *basename,
+ gboolean prepend_basename,
+ gboolean in_thread,
+ GHashTable *pathname_to_g_file)
+{
+ GFileInfo *info;
+ char *root_basename;
+ char *pathname_relative;
+ char *pathname;
+
+ time_t atime, btime, ctime, mtime;
+ long atimeu, btimeu, ctimeu, mtimeu;
+
+ struct archive_entry *sparse;
+
+#ifdef HAVE_STAT
+ struct stat filestat;
+ char *local_pathname;
+#endif
+
+ archive_entry_clear (entry);
+ info = g_file_query_info (file, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, &(arcreate->priv->error));
+ if (info == NULL)
+ return;
+
+ root_basename = g_file_get_basename (root);
+ pathname_relative = g_file_get_relative_path (root, file);
+ pathname = g_strdup_printf ("%s%s%s%s%s",
+ prepend_basename ? basename : "",
+ prepend_basename ? "/" : "",
+ root_basename,
+ "/",
+ pathname_relative != NULL ? pathname_relative : "");
+ g_debug ("autoar_create_do_add_to_archive: %s", pathname);
+
+ archive_entry_set_pathname (entry, pathname);
+ g_free (root_basename);
+ g_free (pathname_relative);
+ g_free (pathname);
+
+ atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
+ btime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CREATED);
+ ctime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CHANGED);
+ mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+
+ atimeu = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
+ btimeu = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CREATED_USEC);
+ ctimeu = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CHANGED_USEC);
+ mtimeu = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
+
+ archive_entry_set_atime (entry, atime, atimeu * 1000);
+ archive_entry_set_birthtime (entry, btime, btimeu * 1000);
+ archive_entry_set_ctime (entry, ctime, ctimeu * 1000);
+ archive_entry_set_mtime (entry, mtime, mtimeu * 1000);
+
+ archive_entry_set_uid (entry, g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID));
+ archive_entry_set_gid (entry, g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID));
+ archive_entry_set_uname (entry, g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER));
+ archive_entry_set_gname (entry, g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP));
+ archive_entry_set_mode (entry, g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE));
+
+ archive_entry_set_size (entry, g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE));
+ archive_entry_set_dev (entry, g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_DEVICE));
+ archive_entry_set_ino64 (entry, g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE));
+ archive_entry_set_nlink (entry, g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_NLINK));
+ archive_entry_set_rdev (entry, g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_RDEV));
+
+ switch (g_file_info_get_file_type (info)) {
+ case G_FILE_TYPE_DIRECTORY:
+ archive_entry_set_filetype (entry, AE_IFDIR);
+ break;
+ case G_FILE_TYPE_SYMBOLIC_LINK:
+ archive_entry_set_filetype (entry, AE_IFLNK);
+ archive_entry_set_symlink (entry, g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET));
+ break;
+ case G_FILE_TYPE_SPECIAL:
+#ifdef HAVE_STAT
+ local_pathname = g_file_get_path (file);
+ if (local_pathname != NULL && stat (local_pathname, &filestat) >= 0) {
+ if (filestat.st_mode & S_IFSOCK)
+ archive_entry_set_filetype (entry, AE_IFSOCK);
+ else if (filestat.st_mode & S_IFBLK)
+ archive_entry_set_filetype (entry, AE_IFBLK);
+ else if (filestat.st_mode & S_IFCHR)
+ archive_entry_set_filetype (entry, AE_IFCHR);
+ else if (filestat.st_mode & S_IFIFO)
+ archive_entry_set_filetype (entry, AE_IFIFO);
+ else
+ archive_entry_set_filetype (entry, AE_IFREG);
+ g_free (local_pathname);
+ } else {
+ archive_entry_set_filetype (entry, AE_IFREG);
+ }
+ break;
+#endif
+ case G_FILE_TYPE_UNKNOWN:
+ case G_FILE_TYPE_SHORTCUT:
+ case G_FILE_TYPE_MOUNTABLE:
+ case G_FILE_TYPE_REGULAR:
+ default:
+ archive_entry_set_filetype (entry, AE_IFREG);
+ break;
+ }
+
+ g_hash_table_insert (pathname_to_g_file,
+ g_strdup (archive_entry_pathname (entry)),
+ g_object_ref (file));
+
+ archive_entry_linkify (resolver, &entry, &sparse);
+
+ if (entry != NULL) {
+ GFile *file_to_read;
+ const char *pathname_in_entry;
+ pathname_in_entry = archive_entry_pathname (entry);
+ file_to_read = g_hash_table_lookup (pathname_to_g_file, pathname_in_entry);
+ autoar_create_do_write_data (arcreate, a, entry, file_to_read, in_thread);
+ g_hash_table_remove (pathname_to_g_file, pathname_in_entry);
+ }
+
+ if (sparse != NULL) {
+ GFile *file_to_read;
+ const char *pathname_in_entry;
+ pathname_in_entry = archive_entry_pathname (entry);
+ file_to_read = g_hash_table_lookup (pathname_to_g_file, pathname_in_entry);
+ autoar_create_do_write_data (arcreate, a, sparse, file_to_read, in_thread);
+ g_hash_table_remove (pathname_to_g_file, pathname_in_entry);
+ }
+
+ g_object_unref (info);
+}
+
+static void
+autoar_create_do_recursive_read (AutoarCreate *arcreate,
+ struct archive *a,
+ struct archive_entry *entry,
+ struct archive_entry_linkresolver *resolver,
+ GFile *root,
+ GFile *file,
+ const char *basename,
+ gboolean prepend_basename,
+ gboolean in_thread,
+ GHashTable *pathname_to_g_file)
+{
+ GFileEnumerator *enumerator;
+ GFileInfo *info;
+ GFile *thisfile;
+ const char *thisname;
+
+ enumerator = g_file_enumerate_children (file,
+ "standard::*",
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL,
+ &(arcreate->priv->error));
+ if (enumerator == NULL)
+ return;
+
+ while ((info = g_file_enumerator_next_file (enumerator, NULL, &(arcreate->priv->error))) != NULL) {
+ thisname = g_file_info_get_name (info);
+ thisfile = g_file_get_child (file, thisname);
+ autoar_create_do_add_to_archive (arcreate, a, entry, resolver, root,
+ thisfile, basename, prepend_basename,
+ in_thread, pathname_to_g_file);
+ if (arcreate->priv->error != NULL) {
+ g_object_unref (thisfile);
+ g_object_unref (info);
+ break;
+ }
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
+ autoar_create_do_recursive_read (arcreate, a, entry, resolver, root,
+ thisfile, basename, prepend_basename,
+ in_thread, pathname_to_g_file);
+ g_object_unref (thisfile);
+ g_object_unref (info);
+
+ if (arcreate->priv->error != NULL)
+ break;
+ }
+}
+
static void
autoar_create_class_init (AutoarCreateClass *klass)
{
@@ -333,10 +676,10 @@ autoar_create_class_init (AutoarCreateClass *klass)
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
- g_object_class_install_property (object_class, PROP_SIZE,
+ g_object_class_install_property (object_class, PROP_SIZE, /* This propery is unused! */
g_param_spec_uint64 ("size",
"Size",
- "Unused property",
+ "Total bytes will be read from disk",
0, G_MAXUINT64, 0,
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME |
@@ -346,7 +689,7 @@ autoar_create_class_init (AutoarCreateClass *klass)
g_object_class_install_property (object_class, PROP_COMPLETED_SIZE,
g_param_spec_uint64 ("completed-size",
"Read file size",
- "Bytes written to the archive",
+ "Bytes read from disk",
0, G_MAXUINT64, 0,
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME |
@@ -452,6 +795,7 @@ autoar_create_newv (AutoarPref *arpref,
AutoarCreate *arcreate;
g_return_val_if_fail (source != NULL, NULL);
+ g_return_val_if_fail (*source != NULL, NULL);
g_return_val_if_fail (output != NULL, NULL);
arcreate = g_object_new (AUTOAR_TYPE_CREATE,
@@ -492,7 +836,266 @@ autoar_create_run (AutoarCreate *arcreate,
{
struct archive *a;
struct archive_entry *entry;
+ struct archive_entry_linkresolver *resolver;
+
+ AutoarPrefFormat format;
+ AutoarPrefFilter filter;
+ const char *format_extension;
+ const char *filter_extension;
+
+ const char *basename;
+ gboolean prepend_basename;
+
+ GFile *file_source;
+ GFile *file_output;
+ GFile *file_dest;
+ char *source_basename;
+ char *source_basename_noext;
+ char *dest_basename;
+
+ GHashTable *pathname_to_g_file;
+
+ int i, r;
+
+ g_return_if_fail (AUTOAR_IS_CREATE (arcreate));
+ g_return_if_fail (arcreate->priv->source != NULL);
+ g_return_if_fail (arcreate->priv->output != NULL);
+
+ /* A string array without a string is not allowed */
+ g_return_if_fail (*(arcreate->priv->source) != NULL);
+
+ format = autoar_pref_get_default_format (arcreate->priv->arpref);
+ filter = autoar_pref_get_default_filter (arcreate->priv->arpref);
+ g_return_if_fail (format > 0 && format < AUTOAR_PREF_FORMAT_LAST);
+ g_return_if_fail (filter > 0 && filter < AUTOAR_PREF_FILTER_LAST);
+
+ a = archive_write_new ();
+ archive_write_set_bytes_in_last_block (a, 1);
+ switch (filter) {
+ case AUTOAR_PREF_FILTER_COMPRESS:
+ archive_write_add_filter_compress (a);
+ filter_extension = ".Z";
+ break;
+ case AUTOAR_PREF_FILTER_GZIP:
+ archive_write_add_filter_gzip (a);
+ filter_extension = ".gz";
+ break;
+ case AUTOAR_PREF_FILTER_BZIP2:
+ archive_write_add_filter_bzip2 (a);
+ filter_extension = ".bz2";
+ break;
+ case AUTOAR_PREF_FILTER_XZ:
+ archive_write_add_filter_xz (a);
+ filter_extension = ".xz";
+ break;
+ case AUTOAR_PREF_FILTER_LZMA:
+ archive_write_add_filter_lzma (a);
+ filter_extension = ".lzma";
+ break;
+ case AUTOAR_PREF_FILTER_LZIP:
+ archive_write_add_filter_lzip (a);
+ filter_extension = ".lz";
+ break;
+ case AUTOAR_PREF_FILTER_LZOP:
+ archive_write_add_filter_lzop (a);
+ filter_extension = ".lzo";
+ break;
+ case AUTOAR_PREF_FILTER_GRZIP:
+ archive_write_add_filter_grzip (a);
+ filter_extension = ".grz";
+ break;
+ case AUTOAR_PREF_FILTER_LRZIP:
+ archive_write_add_filter_lrzip (a);
+ filter_extension = ".lrz";
+ break;
+ case AUTOAR_PREF_FILTER_NONE:
+ default:
+ filter_extension = "";
+ }
+
+ switch (format) {
+ case AUTOAR_PREF_FORMAT_ZIP:
+ archive_write_set_format_zip (a);
+ format_extension = ".zip";
+ break;
+ case AUTOAR_PREF_FORMAT_TAR:
+ archive_write_set_format_pax_restricted (a);
+ format_extension = ".tar";
+ break;
+ case AUTOAR_PREF_FORMAT_CPIO:
+ archive_write_set_format_cpio (a);
+ format_extension = ".cpio";
+ break;
+ case AUTOAR_PREF_FORMAT_7ZIP:
+ archive_write_set_format_7zip (a);
+ format_extension = ".7z";
+ break;
+ case AUTOAR_PREF_FORMAT_AR_BSD:
+ archive_write_set_format_ar_bsd (a);
+ format_extension = ".a";
+ break;
+ case AUTOAR_PREF_FORMAT_AR_SVR4:
+ archive_write_set_format_ar_svr4 (a);
+ format_extension = ".a";
+ break;
+ case AUTOAR_PREF_FORMAT_CPIO_NEWC:
+ archive_write_set_format_cpio_newc (a);
+ format_extension = ".cpio";
+ break;
+ case AUTOAR_PREF_FORMAT_GNUTAR:
+ archive_write_set_format_gnutar (a);
+ format_extension = ".tar";
+ break;
+ case AUTOAR_PREF_FORMAT_ISO9660:
+ archive_write_set_format_iso9660 (a);
+ format_extension = ".iso";
+ break;
+ case AUTOAR_PREF_FORMAT_PAX:
+ archive_write_set_format_pax (a);
+ format_extension = ".tar";
+ break;
+ case AUTOAR_PREF_FORMAT_XAR:
+ archive_write_set_format_xar (a);
+ format_extension = ".xar";
+ break;
+ default:
+ format_extension = "";
+ }
+
+ /* Step 1: Set the destination file name
+ * Use the first source file name */
+ g_debug ("autoar_extract_run: Step 1, Filename");
+ basename = *(arcreate->priv->source);
+ file_source = g_file_new_for_commandline_arg (basename);
+ file_output = g_file_new_for_commandline_arg (arcreate->priv->output);
+ source_basename = g_file_get_basename (file_source);
+ source_basename_noext = autoar_common_get_basename_remove_extension (source_basename);
+
+ dest_basename = g_strconcat (source_basename_noext,
+ format_extension,
+ filter_extension,
+ NULL);
+ file_dest = g_file_get_child (file_output, dest_basename);
+
+ for (i = 1; g_file_query_exists (file_dest, NULL); i++) {
+ g_free (dest_basename);
+ g_object_unref (file_dest);
+ dest_basename = g_strdup_printf ("%s(%d)%s%s",
+ source_basename_noext,
+ i,
+ format_extension,
+ filter_extension);
+ file_dest = g_file_get_child (file_output, dest_basename);
+ }
+
+ arcreate->priv->dest = g_object_ref (file_dest);
+ autoar_common_g_signal_emit (in_thread, arcreate,
+ autoar_create_signals[DECIDE_DEST],
+ 0, file_dest);
+
+ g_object_unref (file_source);
+ g_object_unref (file_output);
+ g_object_unref (file_dest);
+ g_free (source_basename);
+ g_free (source_basename_noext);
+ g_free (dest_basename);
+
+ /* Step 2: Create and open the new archive file */
+ g_debug ("autoar_extract_run: Step 2, Create and Write");
+ r = archive_write_open (a, arcreate,
+ libarchive_write_open_cb,
+ libarchive_write_write_cb,
+ libarchive_write_close_cb);
+ if (r != ARCHIVE_OK) {
+ archive_write_free (a);
+ if (arcreate->priv->error == NULL)
+ arcreate->priv->error = g_error_new_literal (autoar_create_quark,
+ archive_errno (a),
+ archive_error_string (a));
+ autoar_common_g_signal_emit (in_thread, arcreate,
+ autoar_create_signals[ERROR],
+ 0, arcreate->priv->error);
+ return;
+ }
+
+
+ /* Check whether we have multiple source files */
+ if (arcreate->priv->source[1] == NULL)
+ prepend_basename = FALSE;
+ else
+ prepend_basename = TRUE;
+
+ entry = archive_entry_new ();
+ resolver = archive_entry_linkresolver_new ();
+ archive_entry_linkresolver_set_strategy (resolver, archive_format (a));
+ pathname_to_g_file = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ for (i = 0; arcreate->priv->source[i] != NULL; i++) {
+ GFile *file;
+ GFileInfo *fileinfo;
+
+ file = g_file_new_for_commandline_arg (arcreate->priv->source[i]);
+ fileinfo = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL,
+ &(arcreate->priv->error));
+ if (arcreate->priv->error != NULL) {
+ autoar_common_g_signal_emit (in_thread, arcreate,
+ autoar_create_signals[ERROR],
+ 0, arcreate->priv->error);
+ g_object_unref (file);
+ g_object_unref (fileinfo);
+ archive_write_free (a);
+ archive_entry_free (entry);
+ archive_entry_linkresolver_free (resolver);
+ g_hash_table_unref (pathname_to_g_file);
+ return;
+ }
+
+ autoar_create_do_add_to_archive (arcreate, a, entry, resolver, file, file,
+ basename, prepend_basename, in_thread,
+ pathname_to_g_file);
+
+ if (g_file_info_get_file_type (fileinfo) == G_FILE_TYPE_DIRECTORY)
+ autoar_create_do_recursive_read (arcreate, a, entry, resolver, file, file,
+ basename, prepend_basename, in_thread,
+ pathname_to_g_file);
+
+ g_object_unref (file);
+ g_object_unref (fileinfo);
+
+ if (arcreate->priv->error != NULL) {
+ autoar_common_g_signal_emit (in_thread, arcreate,
+ autoar_create_signals[ERROR],
+ 0, arcreate->priv->error);
+ archive_write_free (a);
+ archive_entry_free (entry);
+ archive_entry_linkresolver_free (resolver);
+ g_hash_table_unref (pathname_to_g_file);
+ return;
+ }
+ }
+
+ archive_entry_free (entry);
+ archive_entry_linkresolver_free (resolver);
+ g_hash_table_unref (pathname_to_g_file);
+
+ r = archive_write_close (a);
+ if (r != ARCHIVE_OK) {
+ if (arcreate->priv->error == NULL)
+ arcreate->priv->error = g_error_new_literal (autoar_create_quark,
+ archive_errno (a),
+ archive_error_string (a));
+
+ archive_write_free (a);
+ return;
+ }
+
+ archive_write_free (a);
+ autoar_common_g_signal_emit (in_thread, arcreate,
+ autoar_create_signals[COMPLETED], 0);
}
void