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