c6366dde732a5b74d4b162abd0a9c3d582ba0242
[claws.git] / src / plugins / archive / libarchive_archive.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2018 Michael Rasmussen and the Claws Mail Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #  include "config.h"
21 #include "claws-features.h"
22 #endif
23
24 #include <glib.h>
25 #include <glib/gi18n.h>
26 #include <glib/gstdio.h>
27
28 #include "libarchive_archive.h"
29
30 #ifndef _TEST
31 #       include "archiver.h"
32 #       include "utils.h"
33 #       include "mainwindow.h"
34 #   include "folder.h"
35 #endif
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39
40 #include <archive.h>
41 #include <archive_entry.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <dirent.h>
48 #include <libgen.h>
49
50 #define READ_BLOCK_SIZE 10240
51
52 struct file_info {
53         char* path;
54         char* name;
55 };
56
57 static GSList* msg_trash_list = NULL;
58 static GSList* file_list = NULL;
59 static gboolean stop_action = FALSE;
60
61 #ifdef _TEST
62 static int permissions = 0;
63 #endif
64
65 static void free_msg_trash(MsgTrash* trash) {
66     if (trash) {
67         gchar *name = folder_item_get_name(trash->item);
68
69         debug_print("Freeing files in %s\n", name);
70         g_free(name);
71         if (trash->msgs) {
72             g_slist_free(trash->msgs);
73         }
74         g_free(trash);
75     }
76 }
77
78 MsgTrash* new_msg_trash(FolderItem* item) {
79     MsgTrash* msg_trash;
80     FolderType  type;
81
82     g_return_val_if_fail(item != NULL, NULL);
83
84     /* FolderType must be F_MH, F_MBOX, F_MAILDIR or F_IMAP */
85     type = item->folder->klass->type;
86     if (!(type == F_MH || type == F_MBOX || 
87             type == F_MAILDIR || type == F_IMAP))
88        return NULL; 
89     msg_trash = g_new0(MsgTrash, 1);
90     msg_trash->item = item;
91     msg_trash->msgs = NULL;
92     msg_trash_list = g_slist_prepend(msg_trash_list, msg_trash);
93     
94     return msg_trash;
95     }
96
97 void archive_free_archived_files() {
98     MsgTrash* mt = NULL;
99     gint    res;
100     GSList* l = NULL;
101    
102     for (l = msg_trash_list; l; l = g_slist_next(l)) {
103         gchar *name = folder_item_get_name(mt->item);
104         mt = (MsgTrash *) l->data;
105         debug_print("Trashing messages in folder: %s\n", 
106                 name);
107         g_free(name);
108         res = folder_item_remove_msgs(mt->item, mt->msgs);
109         debug_print("Result was %d\n", res);
110         free_msg_trash(mt);
111     }
112     g_slist_free(msg_trash_list);
113     msg_trash_list = NULL;
114 }
115
116 void archive_add_msg_mark(MsgTrash* trash, MsgInfo* msg) {
117     g_return_if_fail(trash != NULL || msg != NULL);
118     debug_print("Marking msg #%d for removal\n", msg->msgnum);
119     trash->msgs = g_slist_prepend(trash->msgs, msg);
120 }
121
122 static void free_all(GDate* date, gchar** parts) {
123     if (date)
124         g_date_free(date);
125     if (parts)
126         g_strfreev(parts);
127 }
128
129 static gboolean is_iso_string(gchar** items) {
130     int i = -1;
131     gchar* item;
132
133     while (*items) {
134         i++;
135         item = *items++;
136         debug_print("Date part %d: %s\n", i, item);
137         switch(i) {
138             case 0:
139                 if (strlen(item) != 4)
140                     return FALSE;
141                 break;
142             case 1:
143             case 2:
144                 if (strlen(item) != 2)
145                     return FALSE;
146                 break;
147             default:
148                 return FALSE;
149         }
150     }
151     debug_print("Leaving\n");
152     return (i == 2);
153 }
154
155 static GDate* iso2GDate(const gchar* date) {
156     GDate*  gdate;
157     gchar** parts;
158     int     i;
159
160     g_return_val_if_fail(date != NULL, NULL);
161
162     gdate = g_date_new();
163     parts = g_strsplit(date, "-", 3);
164     if (!parts)
165         return NULL;
166     if (! is_iso_string(parts)) {
167         free_all(gdate, parts);
168         return NULL;
169     }
170     for (i = 0; i < 3; i++) {
171         int t = atoi(parts[i]);
172         switch (i) {
173             case 0: 
174                 if (t < 1 || t > 9999) {
175                     free_all(gdate, parts);
176                     return NULL;
177                 }
178                 g_date_set_year(gdate, t);
179                 break;
180             case 1:
181                 if (t < 1 || t > 12) {
182                     free_all(gdate, parts);
183                     return NULL;
184                 }
185                 g_date_set_month(gdate, t);
186                 break;
187             case 2:
188                 if (t < 1 || t > 31) {
189                     free_all(gdate, parts);
190                     return NULL;
191                 }
192                 g_date_set_day(gdate, t);
193                 break;
194         }
195     }
196     g_strfreev(parts);
197     return gdate;
198 }
199
200 gboolean before_date(time_t msg_mtime, const gchar* before) {
201     gchar*      pos = NULL;
202     GDate*      date;
203     GDate*      file_t;
204     gboolean    res;
205
206     debug_print("Cut-off date: %s\n", before);
207     if ((date = iso2GDate(before)) == NULL) {
208         g_warning("bad date format: %s", before);
209         return FALSE;
210     }
211
212     file_t = g_date_new();
213     g_date_set_time_t(file_t, msg_mtime);
214
215     if (debug_get_mode()) {
216         pos = g_new0(char, 100);
217         g_date_strftime(pos, 100, "%F", file_t);
218         fprintf(stderr, "File date: %s\n", pos);
219         g_free(pos);
220     }
221
222     if (! g_date_valid(file_t)) {
223         g_warning("invalid msg date");
224         return FALSE;
225     }
226
227     res = (g_date_compare(file_t, date) >= 0) ? FALSE : TRUE;
228     g_date_free(file_t);
229     return res;
230 }
231    
232 static void archive_free_file_info(struct file_info* file) {
233         if (! file)
234                 return;
235         if (file->path)
236                 g_free(file->path);
237         if (file->name)
238                 g_free(file->name);
239         g_free(file);
240         file = NULL;
241 }
242
243 void stop_archiving() {
244         debug_print("stop action set to true\n");
245         stop_action = TRUE;
246 }
247
248 void archive_free_file_list(gboolean md5, gboolean rename) {
249         struct file_info* file = NULL;
250         gchar* path = NULL;
251
252         debug_print("freeing file list\n");
253         if (! file_list)
254                 return;
255         while (file_list) {
256                 file = (struct file_info *) file_list->data;
257                 if (!rename && md5 && g_str_has_suffix(file->name, ".md5")) {
258                         path = g_strdup_printf("%s/%s", file->path, file->name);
259                         debug_print("unlinking %s\n", path);
260                         if (g_unlink(path) < 0)
261                                 FILE_OP_ERROR(path, "g_unlink");
262                         g_free(path);
263                 }
264                 if (rename) {
265                         path = g_strdup_printf("%s/%s", file->path, file->name);
266                         debug_print("unlinking %s\n", path);
267                         if (g_unlink(path) < 0)
268                                 FILE_OP_ERROR(path, "g_unlink");
269                         g_free(path);
270                 }
271                 archive_free_file_info(file);
272                 file_list->data = NULL;
273                 file_list = g_slist_next(file_list);
274         }
275         if (file_list) {
276                 g_slist_free(file_list);
277                 file_list = NULL;
278         }
279 }
280
281 static struct file_info* archive_new_file_info() {
282         struct file_info* new_file_info = malloc(sizeof(struct file_info));
283
284         new_file_info->path = NULL;
285         new_file_info->name = NULL;
286         return new_file_info;
287 }
288
289 static void archive_add_to_list(struct file_info* file) {
290         if (! file)
291                 return;
292         file_list = g_slist_prepend(file_list, (gpointer) file);
293 }
294
295 static gchar* strip_leading_dot_slash(gchar* path) {
296         if (path && strlen(path) > 1 && path[0] == '.' && path[1] == '/')
297                 return g_strdup(&(path[2]));
298
299         return g_strdup(path);
300 }
301
302 static gchar* get_full_path(struct file_info* file) {
303         char* path = malloc(PATH_MAX);
304
305         if (file->path && *(file->path))
306                 sprintf(path, "%s/%s", file->path, file->name);
307         else
308                 sprintf(path, "%s", file->name);
309         return path;
310 }
311
312 #ifdef _TEST
313 static gchar* strip_leading_slash(gchar* path) {
314         gchar* stripped = path;
315         gchar* result = NULL;
316
317         if (stripped && stripped[0] == '/') {
318                 ++stripped;
319                 result = g_strdup(stripped);
320         }
321         else
322                 result = g_strdup(path);
323         return result;
324 }
325
326 static int archive_get_permissions() {
327         return permissions;
328 }
329
330
331 void archive_set_permissions(int perm) {
332         permissions = perm;
333 }
334
335 static int archive_copy_data(struct archive* in, struct archive* out) {
336         const void* buf;
337         size_t size;
338         off_t offset;
339         int res = ARCHIVE_OK;
340
341         while (res == ARCHIVE_OK) {
342                 res = archive_read_data_block(in, &buf, &size, &offset);
343                 if (res == ARCHIVE_OK) {
344                         res = archive_write_data_block(out, buf, size, offset);
345                 }
346         }
347         return (res == ARCHIVE_EOF) ? ARCHIVE_OK : res;
348 }
349 #endif
350
351 void archive_add_file(gchar* path) {
352         struct file_info* file;
353         gchar* filename = NULL;
354
355         g_return_if_fail(path != NULL);
356
357 #ifndef _TEST
358         debug_print("add %s to list\n", path);
359 #endif
360         filename = g_strrstr_len(path, strlen(path), "/");
361         if (! filename)
362                 g_warning("no filename in path '%s'", path);
363         g_return_if_fail(filename != NULL);
364
365         filename++;
366         file = archive_new_file_info();
367         file->name = g_strdup(filename);
368         file->path = strip_leading_dot_slash(dirname(path));
369         archive_add_to_list(file);
370 }
371
372 GSList* archive_get_file_list() {
373         return file_list;
374 }
375
376 #ifdef _TEST
377 const gchar* archive_extract(const char* archive_name, int flags) {
378         struct archive* in;
379         struct archive* out;
380         struct archive_entry* entry;
381         int res = ARCHIVE_OK;
382         gchar* buf = NULL;
383         const char* result == NULL;
384
385         g_return_val_if_fail(archive_name != NULL, ARCHIVE_FATAL);
386
387         fprintf(stdout, "%s: extracting\n", archive_name);
388         in = archive_read_new();
389         if ((res = archive_read_support_format_tar(in)) == ARCHIVE_OK) {
390                 if ((res = archive_read_support_compression_gzip(in)) == ARCHIVE_OK) {
391 #if ARCHIVE_VERSION_NUMBER < 3000000
392                         if ((res = archive_read_open_file(
393 #else
394                         if ((res = archive_read_open_filename(
395 #endif
396                                 in, archive_name, READ_BLOCK_SIZE)) != ARCHIVE_OK) {
397                                 g_warning("%s: %s", archive_name, archive_error_string(in));
398                                 result = archive_error_string(in);
399                         }
400                         else {
401                                 out = archive_write_disk_new();
402                                 if ((res = archive_write_disk_set_options(
403                                                                 out, flags)) == ARCHIVE_OK) {
404                                         res = archive_read_next_header(in, &entry);
405                                         while (res == ARCHIVE_OK) {
406                                                 res = archive_write_header(out, entry);
407                                                 if (res != ARCHIVE_OK) {
408                                                         g_warning("%s", archive_error_string(out));
409                                                         /* skip this file an continue */
410                                                         res = ARCHIVE_OK;
411                                                 }
412                                                 else {
413                                                         res = archive_copy_data(in, out);
414                                                         if (res != ARCHIVE_OK) {
415                                                                 g_warning("%s", archive_error_string(in));
416                                                                 /* skip this file an continue */
417                                                                 res = ARCHIVE_OK;
418                                                         }
419                                                         else
420                                                                 res = archive_read_next_header(in, &entry);
421                                                 }
422                                         }
423                                         if (res == ARCHIVE_EOF)
424                                                 res = ARCHIVE_OK;
425                                         if (res != ARCHIVE_OK) {
426                                                 gchar *e = archive_error_string(in);
427                                                 g_warning("%s: %s", archive_name, e? e: "unknown error");
428                                                 result = e;
429                                         }
430                                 }
431                                 else
432                                         result = archive_error_string(out);
433                                 archive_read_close(in);
434                         }
435 #if ARCHIVE_VERSION_NUMBER < 3000000
436                         archive_read_finish(in);
437 #else
438                         archive_read_free(in);
439 #endif
440                 }
441                 else
442                         result = archive_error_string(in);
443         }
444         else
445                 result = archive_error_string(in);
446         return result;
447 }
448 #endif
449
450 const gchar* archive_create(const char* archive_name, GSList* files,
451                         COMPRESS_METHOD method, ARCHIVE_FORMAT format) {
452         struct archive* arch;
453
454 #ifndef _TEST
455         gint num = 0;
456         gint total = g_slist_length (files);
457 #endif
458
459         g_return_val_if_fail(files != NULL, "No files for archiving");
460
461         debug_print("File: %s\n", archive_name);
462         arch = archive_write_new();
463         switch (method) {
464                 case GZIP:
465 #if ARCHIVE_VERSION_NUMBER < 3000000
466                         if (archive_write_set_compression_gzip(arch) != ARCHIVE_OK)
467 #else
468                         if (archive_write_add_filter_gzip(arch) != ARCHIVE_OK)
469 #endif
470                                 return archive_error_string(arch);
471                         break;
472                 case BZIP2:
473 #if ARCHIVE_VERSION_NUMBER < 3000000
474                         if (archive_write_set_compression_bzip2(arch) != ARCHIVE_OK)
475 #else
476                         if (archive_write_add_filter_bzip2(arch) != ARCHIVE_OK)
477 #endif
478                                 return archive_error_string(arch);
479                         break;
480                 case COMPRESS:
481 #if ARCHIVE_VERSION_NUMBER < 3000000
482                         if (archive_write_set_compression_compress(arch) != ARCHIVE_OK)
483 #else
484                         if (archive_write_add_filter_compress(arch) != ARCHIVE_OK)
485 #endif
486                                 return archive_error_string(arch);
487                         break;
488 #if ARCHIVE_VERSION_NUMBER >= 2006990
489                 case LZMA:
490 #if ARCHIVE_VERSION_NUMBER < 3000000
491                         if (archive_write_set_compression_lzma(arch) != ARCHIVE_OK)
492 #else
493                         if (archive_write_add_filter_lzma(arch) != ARCHIVE_OK)
494 #endif
495                                 return archive_error_string(arch);
496                         break;
497                 case XZ:
498 #if ARCHIVE_VERSION_NUMBER < 3000000
499                         if (archive_write_set_compression_xz(arch) != ARCHIVE_OK)
500 #else
501                         if (archive_write_add_filter_xz(arch) != ARCHIVE_OK)
502 #endif
503                                 return archive_error_string(arch);
504                         break;
505 #endif
506 #if ARCHIVE_VERSION_NUMBER >= 3000000
507                 case LZIP:
508                         if (archive_write_add_filter_lzip(arch) != ARCHIVE_OK)
509                                 return archive_error_string(arch);
510                         break;
511 #endif
512 #if ARCHIVE_VERSION_NUMBER >= 3001000
513                 case LRZIP:
514                         if (archive_write_add_filter_lrzip(arch) != ARCHIVE_OK)
515                                 return archive_error_string(arch);
516                         break;
517                 case LZOP:
518                         if (archive_write_add_filter_lzop(arch) != ARCHIVE_OK)
519                                 return archive_error_string(arch);
520                         break;
521                 case GRZIP:
522                         if (archive_write_add_filter_grzip(arch) != ARCHIVE_OK)
523                                 return archive_error_string(arch);
524                         break;
525 #endif
526 #if ARCHIVE_VERSION_NUMBER >= 3001900
527                 case LZ4:
528                         if (archive_write_add_filter_lz4(arch) != ARCHIVE_OK)
529                                 return archive_error_string(arch);
530                         break;
531 #endif
532                 case NO_COMPRESS:
533 #if ARCHIVE_VERSION_NUMBER < 3000000
534                         if (archive_write_set_compression_none(arch) != ARCHIVE_OK)
535 #else
536                         if (archive_write_add_filter_none(arch) != ARCHIVE_OK)
537 #endif
538                                 return archive_error_string(arch);
539                         break;
540         }
541         switch (format) {
542                 case TAR:
543                         if (archive_write_set_format_ustar(arch) != ARCHIVE_OK)
544                                 return archive_error_string(arch);
545                         break;
546                 case SHAR:
547                         if (archive_write_set_format_shar(arch) != ARCHIVE_OK)
548                                 return archive_error_string(arch);
549                         break;
550                 case PAX:
551                         if (archive_write_set_format_pax(arch) != ARCHIVE_OK)
552                                 return archive_error_string(arch);
553                         break;
554                 case CPIO:
555                         if (archive_write_set_format_cpio(arch) != ARCHIVE_OK)
556                                 return archive_error_string(arch);
557                         break;
558                 case NO_FORMAT:
559                         return "Missing archive format";
560         }
561 #if ARCHIVE_VERSION_NUMBER < 3000000
562         if (archive_write_open_file(arch, archive_name) != ARCHIVE_OK)
563 #else
564         if (archive_write_open_filename(arch, archive_name) != ARCHIVE_OK)
565 #endif
566                 return archive_error_string(arch);
567
568         while (files && ! stop_action) {
569                 struct file_info* file;
570                 gchar* filename = NULL;
571
572 #ifndef _TEST
573                 set_progress_print_all(num++, total, 30);
574 #endif
575                 file = (struct file_info *) files->data;
576                 if (!file)
577                         continue;
578                 filename = get_full_path(file);
579                 /* libarchive will crash if instructed to add archive to it self */
580                 if (g_utf8_collate(archive_name, filename) == 0) {
581                         g_warning("%s: not dumping to '%s'", archive_name, filename);
582 #ifndef _TEST
583                         debug_print("%s: not dumping to '%s'\n", archive_name, filename);
584 #endif
585                 }
586                 else {
587                         struct archive_entry* entry;
588                         char* buf = NULL;
589                         ssize_t len;
590                         GError* err = NULL;
591                         GStatBuf st;
592                         int fd;
593                         gchar* msg = NULL;
594
595 #ifndef _TEST
596                         debug_print("Adding: %s\n", filename);
597                         msg = g_strdup_printf("%s", filename);
598                         set_progress_file_label(msg);
599                         g_free(msg);
600 #endif
601                         if ((fd = g_open(filename, O_RDONLY, 0)) == -1) {
602                                 FILE_OP_ERROR(filename, "g_open");
603                         }
604                         else {
605                                 if (g_stat(filename, &st) == -1) {
606                                         FILE_OP_ERROR(filename, "g_stat");
607                                 } else {
608                                         entry = archive_entry_new();
609                                         archive_entry_copy_stat(entry, &st);
610                                         archive_entry_set_pathname(entry, filename);
611                                         if (S_ISLNK(st.st_mode)) {
612
613                                                 buf = g_file_read_link(filename, &err);
614                                                 if (err) {
615                                                         FILE_OP_ERROR(filename, "g_file_read_link");
616                                                         g_clear_error(&err);
617                                                 } else {
618                                                         archive_entry_set_symlink(entry, buf);
619                                                         g_free(buf);
620                                                         archive_entry_set_size(entry, 0);
621                                                         archive_write_header(arch, entry);
622                                                 }
623                                         }
624                                         else {
625                                                 if (archive_write_header(arch, entry) != ARCHIVE_OK)
626                                                         g_warning("%s", archive_error_string(arch));
627                                                 if ((buf = malloc(READ_BLOCK_SIZE)) != NULL) {
628                                                         len = read(fd, buf, READ_BLOCK_SIZE);
629                                                         while (len > 0) {
630                                                                 if (archive_write_data(arch, buf, len) == -1)
631                                                                         g_warning("%s", archive_error_string(arch));
632                                                                 memset(buf, 0, READ_BLOCK_SIZE);
633                                                                 len = read(fd, buf, READ_BLOCK_SIZE);
634                                                         }
635                                                         g_free(buf);
636                                                 }
637                                         }
638                                         archive_entry_free(entry);
639                                 }
640                                 if (!g_close(fd, &err) || err) {
641                                         FILE_OP_ERROR(filename, "g_close");
642                                         if (err)
643                                                 g_clear_error(&err);
644                 }
645                         }
646                 }
647                 g_free(filename);
648                 files = g_slist_next(files);
649         }
650 #ifndef _TEST
651         if (stop_action)
652                 unlink(archive_name);
653         stop_action = FALSE;
654 #endif
655         archive_write_close(arch);
656 #if ARCHIVE_VERSION_NUMBER < 3000000
657         archive_write_finish(arch);
658 #else
659         archive_write_free(arch);
660 #endif
661         return NULL;
662 }
663
664 #ifdef _TEST
665 void archive_scan_folder(const char* dir) {
666         GStatBuf st;
667         DIR* root;
668         struct dirent* ent;
669         gchar cwd[PATH_MAX];
670         gchar path[PATH_MAX];
671         
672         getcwd(cwd, PATH_MAX);
673
674         if (g_stat(dir, &st) == -1)
675                 return;
676         if (! S_ISDIR(st.st_mode))
677                 return;
678         if (!(root = opendir(dir)))
679                 return;
680         chdir(dir);
681
682         while ((ent = readdir(root)) != NULL) {
683                 if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
684                         continue;
685                 if (g_stat(ent->d_name, &st) == -1) {
686                         FILE_OP_ERROR(filename, "g_stat");
687                         continue;
688                 }
689                 sprintf(path, "%s/%s", dir, ent->d_name);
690                 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
691                         archive_add_file(path);
692                 }
693                 else if (S_ISDIR(st.st_mode)) {
694                         archive_scan_folder(path);
695                 }
696         }
697         chdir(cwd);
698         closedir(root);
699 }
700
701 int main(int argc, char** argv) {
702         char* archive = NULL;
703         char buf[PATH_MAX];
704         int pid;
705         int opt;
706         int perm = ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME |
707                 ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_SECURE_SYMLINKS;
708         gchar cwd[PATH_MAX];
709         gboolean remove = FALSE;
710         const char *p = NULL;
711         int res;
712
713         getcwd(cwd, PATH_MAX);
714
715         while (*++argv && **argv == '-') {
716                 p = *argv + 1;
717
718                 while ((opt = *p++) != '\0') {
719                         switch(opt) {
720                                 case 'a':
721                                         if (*p != '\0')
722                                                 archive = (char *) p;
723                                         else
724                                                 archive = *++argv;
725                                         p += strlen(p);
726                                         break;
727                                 case 'r':
728                                         remove = TRUE;
729                                         break;
730                         }
731                 }
732         }
733         if (! archive) {
734                 fprintf(stderr, "Missing archive name!\n");
735                 return EXIT_FAILURE;
736         }
737         if (!*argv) {
738                 fprintf(stderr, "Expected arguments after options!\n");
739                 return EXIT_FAILURE;
740         }
741         
742         while (*argv) {
743                 archive_scan_folder(*argv++);
744                 res = archive_create(archive, file_list);
745                 if (res != ARCHIVE_OK) {
746                         fprintf(stderr, "%s: Creating archive failed\n", archive);
747                         return EXIT_FAILURE;
748                 }
749         }
750         pid = (int) getpid();
751         sprintf(buf, "/tmp/%d", pid);
752         fprintf(stdout, "Creating: %s\n", buf);
753         mkdir(buf, 0700);
754         chdir(buf);
755         if (strcmp(dirname(archive), ".") == 0) 
756                 sprintf(buf, "%s/%s", cwd, basename(archive));
757         else
758                 sprintf(buf, "%s", archive);
759         archive_extract(buf, perm);
760         chdir(cwd);
761         if (remove) {
762                 sprintf(buf, "rm -rf /tmp/%d", pid);
763                 fprintf(stdout, "Executing: %s\n", buf);
764                 system(buf);
765         }
766         archive_free_list(file_list);
767         return EXIT_SUCCESS;
768 }
769 #endif
770
771 void archiver_set_tooltip(GtkWidget* widget, gchar* text) {
772     gtk_widget_set_tooltip_text(widget, text);
773     g_free(text);
774 }