Fix #1240: Regression: Option to open new full-function window directly is missing
[geeqie.git] / src / archives.cc
1 /*
2  * Copyright (C) 2008 - 2016 The Geeqie Team
3  *
4  * Authors: Vladimir Nadvornik, Laurent Monin
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "archives.h"
22
23 #include <config.h>
24
25 #include "debug.h"
26 #include "intl.h"
27
28 #if HAVE_ARCHIVE
29 #include <unistd.h>
30
31 #include <cerrno>
32 #include <cstdint>
33 #include <cstring>
34
35 #include <archive.h>
36 #include <archive_entry.h>
37
38 #include "filedata.h"
39 #include "main-defines.h"
40 #include "main.h"
41 #include "ui-fileops.h"
42
43 /* Copied from the libarchive .repo. examples */
44
45 namespace
46 {
47
48 int verbose = 0;
49
50 void msg(const char *m)
51 {
52         log_printf("Open Archive - libarchive error: %s \n", m);
53 }
54
55 void errmsg(const char *m)
56 {
57         if (m == nullptr)
58                 {
59                 m = "Error: No error description provided.\n";
60                 }
61         msg(m);
62 }
63
64 int copy_data(struct archive *ar, struct archive *aw)
65 {
66         int r;
67         const void *buff;
68         size_t size;
69         int64_t offset;
70
71         for (;;)
72                 {
73                 r = archive_read_data_block(ar, &buff, &size, &offset);
74                 if (r == ARCHIVE_EOF)
75                         return (ARCHIVE_OK);
76                 if (r != ARCHIVE_OK)
77                         {
78                         errmsg(archive_error_string(ar));
79                         return (r);
80                         }
81                 r = archive_write_data_block(aw, buff, size, offset);
82                 if (r != ARCHIVE_OK)
83                         {
84                         errmsg(archive_error_string(ar));
85                         return (r);
86                         }
87                 }
88 }
89
90 gboolean extract(const char *filename, bool do_extract, int flags)
91 {
92         struct archive *a;
93         struct archive *ext;
94         struct archive_entry *entry;
95         int r;
96
97         a = archive_read_new();
98         ext = archive_write_disk_new();
99         archive_write_disk_set_options(ext, flags);
100         archive_write_disk_set_standard_lookup(ext);
101         archive_read_support_filter_all(a);
102         archive_read_support_format_all(a);
103
104         if (filename != nullptr && strcmp(filename, "-") == 0)
105                 {
106                 filename = nullptr;
107                 }
108         if ((r = archive_read_open_filename(a, filename, 10240)))
109                 {
110                 errmsg(archive_error_string(a));
111                 errmsg("\n");
112                 return(FALSE);
113                 }
114         for (;;)
115                 {
116                 int needcr = 0;
117
118                 r = archive_read_next_header(a, &entry);
119                 if (r == ARCHIVE_EOF)
120                         {
121                         break;
122                         }
123                 if (r != ARCHIVE_OK)
124                         {
125                         errmsg(archive_error_string(a));
126                         errmsg("\n");
127                         return(FALSE);
128                         }
129                 if (verbose && do_extract)
130                         {
131                         msg("x ");
132                         }
133                 if (verbose || !do_extract)
134                         {
135                         msg(archive_entry_pathname(entry));
136                         msg(" ");
137                         needcr = 1;
138                         }
139                 if (do_extract)
140                         {
141                         r = archive_write_header(ext, entry);
142                         if (r != ARCHIVE_OK)
143                                 {
144                                 errmsg(archive_error_string(a));
145                                 needcr = 1;
146                                 }
147                         else
148                                 {
149                                 r = copy_data(a, ext);
150                                 if (r != ARCHIVE_OK)
151                                         {
152                                         needcr = 1;
153                                         }
154                                 }
155                         }
156                 if (needcr)
157                         {
158                         msg("\n");
159                         }
160                 }
161         archive_read_close(a);
162         archive_read_free(a);
163
164         archive_write_close(ext);
165         archive_write_free(ext);
166         return(TRUE);
167 }
168
169 } // namespace
170
171 gchar *open_archive(const FileData *fd)
172 {
173         int flags;
174         gchar *current_dir;
175         gchar *destination_dir;
176         gboolean success;
177         gint error;
178
179         destination_dir = g_build_filename(g_get_tmp_dir(), GQ_ARCHIVE_DIR, instance_identifier, fd->path, NULL);
180
181         if (!recursive_mkdir_if_not_exists(destination_dir, 0755))
182                 {
183                 log_printf("%s%s%s", _("Open Archive - Cannot create directory: "), destination_dir, "\n");
184                 g_free(destination_dir);
185                 return nullptr;
186                 }
187
188         current_dir = g_get_current_dir();
189         error = chdir(destination_dir);
190         if (error)
191                 {
192                 log_printf("%s%s%s%s%s", _("Open Archive - Cannot change directory to: "), destination_dir, _("\n  Error code: "), strerror(errno), "\n");
193                 g_free(destination_dir);
194                 g_free(current_dir);
195                 return nullptr;
196                 }
197
198         flags = ARCHIVE_EXTRACT_TIME;
199         success = extract(fd->path, true, flags);
200
201         error = chdir(current_dir);
202         if (error)
203                 {
204                 log_printf("%s%s%s%s%s", _("Open Archive - Cannot change directory to: "), current_dir, _("\n  Error code: "), strerror(errno), "\n");
205                 g_free(destination_dir);
206                 g_free(current_dir);
207                 return nullptr;
208                 }
209         g_free(current_dir);
210
211         if (!success)
212                 {
213                 g_free(destination_dir);
214                 destination_dir = nullptr;
215                 }
216
217         return destination_dir;
218 }
219 #else
220 gchar *open_archive(const FileData *)
221 {
222         log_printf("%s", _("Warning: libarchive not installed"));
223         return nullptr;
224 }
225 #endif /* HAVE_ARCHIVE */
226 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */