1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /*
3  * Copyright (C) 2017, Bastien Nocera <hadess@hadess.net>
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 2, or (at your option)
8  * 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, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include "config.h"
21 #include "ev-archive.h"
22 
23 #include <archive.h>
24 #include <archive_entry.h>
25 #include <unarr/unarr.h>
26 #include <gio/gio.h>
27 
28 #define BUFFER_SIZE (64 * 1024)
29 
30 struct _EvArchive {
31 	GObject parent_instance;
32 	EvArchiveType type;
33 
34 	/* libarchive */
35 	struct archive *libar;
36 	struct archive_entry *libar_entry;
37 
38 	/* unarr */
39 	ar_stream *unarr_stream;
40 	ar_archive *unarr;
41 };
42 
43 G_DEFINE_TYPE(EvArchive, ev_archive, G_TYPE_OBJECT);
44 
45 static void
ev_archive_finalize(GObject * object)46 ev_archive_finalize (GObject *object)
47 {
48 	EvArchive *archive = EV_ARCHIVE (object);
49 
50 	switch (archive->type) {
51 	case EV_ARCHIVE_TYPE_RAR:
52 		g_clear_pointer (&archive->unarr, ar_close_archive);
53 		g_clear_pointer (&archive->unarr_stream, ar_close);
54 		break;
55 	case EV_ARCHIVE_TYPE_ZIP:
56 	case EV_ARCHIVE_TYPE_7Z:
57 	case EV_ARCHIVE_TYPE_TAR:
58 	case EV_ARCHIVE_TYPE_RAR5:
59 		g_clear_pointer (&archive->libar, archive_free);
60 		break;
61 	default:
62 		break;
63 	}
64 
65 	G_OBJECT_CLASS (ev_archive_parent_class)->finalize (object);
66 }
67 
68 static void
ev_archive_class_init(EvArchiveClass * klass)69 ev_archive_class_init (EvArchiveClass *klass)
70 {
71         GObjectClass *object_class = (GObjectClass *) klass;
72 
73         object_class->finalize = ev_archive_finalize;
74 }
75 
76 EvArchive *
ev_archive_new(void)77 ev_archive_new (void)
78 {
79 	return g_object_new (EV_TYPE_ARCHIVE, NULL);
80 }
81 
82 static void
libarchive_set_archive_type(EvArchive * archive,EvArchiveType archive_type)83 libarchive_set_archive_type (EvArchive *archive,
84 			     EvArchiveType archive_type)
85 {
86 	archive->type = archive_type;
87 	archive->libar = archive_read_new ();
88 
89 	if (archive_type == EV_ARCHIVE_TYPE_ZIP)
90 		archive_read_support_format_zip (archive->libar);
91 	else if (archive_type == EV_ARCHIVE_TYPE_7Z)
92 		archive_read_support_format_7zip (archive->libar);
93 	else if (archive_type == EV_ARCHIVE_TYPE_TAR)
94 		archive_read_support_format_tar (archive->libar);
95 	else if (archive_type == EV_ARCHIVE_TYPE_RAR5)
96 		archive_read_support_format_rar5 (archive->libar);
97 	else
98 		g_assert_not_reached ();
99 }
100 
101 EvArchiveType
ev_archive_get_archive_type(EvArchive * archive)102 ev_archive_get_archive_type (EvArchive *archive)
103 {
104 	g_return_val_if_fail (EV_IS_ARCHIVE (archive), EV_ARCHIVE_TYPE_NONE);
105 
106 	return archive->type;
107 }
108 
109 gboolean
ev_archive_set_archive_type(EvArchive * archive,EvArchiveType archive_type)110 ev_archive_set_archive_type (EvArchive *archive,
111 			     EvArchiveType archive_type)
112 {
113 	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
114 	g_return_val_if_fail (archive->type == EV_ARCHIVE_TYPE_NONE, FALSE);
115 
116 	switch (archive_type) {
117 	case EV_ARCHIVE_TYPE_RAR:
118 		archive->type = archive_type;
119 		break;
120 	case EV_ARCHIVE_TYPE_ZIP:
121 	case EV_ARCHIVE_TYPE_7Z:
122 	case EV_ARCHIVE_TYPE_TAR:
123 	case EV_ARCHIVE_TYPE_RAR5:
124 		libarchive_set_archive_type (archive, archive_type);
125 		break;
126 	default:
127 		g_assert_not_reached ();
128 	}
129 
130 	return TRUE;
131 }
132 
133 gboolean
ev_archive_open_filename(EvArchive * archive,const char * path,GError ** error)134 ev_archive_open_filename (EvArchive   *archive,
135 			  const char  *path,
136 			  GError     **error)
137 {
138 	int r;
139 	ArArchiveError code;
140 
141 	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
142 	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
143 	g_return_val_if_fail (path != NULL, FALSE);
144 
145 	switch (archive->type) {
146 	case EV_ARCHIVE_TYPE_NONE:
147 		g_assert_not_reached ();
148 	case EV_ARCHIVE_TYPE_RAR:
149 		archive->unarr_stream = ar_open_file (path);
150 		if (archive->unarr_stream == NULL) {
151 			g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
152 					     "Error opening archive");
153 			return FALSE;
154 		}
155 		archive->unarr = ar_open_rar_archive_with_error (archive->unarr_stream, &code);
156 		if (archive->unarr == NULL) {
157 			g_clear_pointer (&archive->unarr_stream, ar_close);
158 			if (code == AR_ARCHIVE_ERROR_RAR5) {
159 				libarchive_set_archive_type (archive, EV_ARCHIVE_TYPE_RAR5);
160 				return ev_archive_open_filename (archive, path, error);
161 			}
162 			g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
163 					     "Error opening RAR archive");
164 			return FALSE;
165 		}
166 		return TRUE;
167 	case EV_ARCHIVE_TYPE_ZIP:
168 	case EV_ARCHIVE_TYPE_7Z:
169 	case EV_ARCHIVE_TYPE_TAR:
170 	case EV_ARCHIVE_TYPE_RAR5:
171 		r = archive_read_open_filename (archive->libar, path, BUFFER_SIZE);
172 		if (r != ARCHIVE_OK) {
173 			g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
174 				     "Error opening archive: %s", archive_error_string (archive->libar));
175 			return FALSE;
176 		}
177 		return TRUE;
178 	}
179 
180 	return FALSE;
181 }
182 
183 static gboolean
libarchive_read_next_header(EvArchive * archive,GError ** error)184 libarchive_read_next_header (EvArchive *archive,
185 			     GError   **error)
186 {
187 	while (1) {
188 		int r;
189 
190 		r = archive_read_next_header (archive->libar, &archive->libar_entry);
191 		if (r != ARCHIVE_OK) {
192 			if (r != ARCHIVE_EOF)
193 				g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
194 					     "Error reading archive: %s", archive_error_string (archive->libar));
195 			return FALSE;
196 		}
197 
198 		if (archive_entry_filetype (archive->libar_entry) != AE_IFREG) {
199 			g_debug ("Skipping '%s' as it's not a regular file",
200 				 archive_entry_pathname (archive->libar_entry));
201 			continue;
202 		}
203 
204 		g_debug ("At header for file '%s'", archive_entry_pathname (archive->libar_entry));
205 
206 		break;
207 	}
208 
209 	return TRUE;
210 }
211 
212 gboolean
ev_archive_read_next_header(EvArchive * archive,GError ** error)213 ev_archive_read_next_header (EvArchive *archive,
214 			     GError   **error)
215 {
216 	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
217 	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
218 
219 	switch (archive->type) {
220 	case EV_ARCHIVE_TYPE_NONE:
221 		g_assert_not_reached ();
222 	case EV_ARCHIVE_TYPE_RAR:
223 		return ar_parse_entry (archive->unarr);
224 	case EV_ARCHIVE_TYPE_ZIP:
225 	case EV_ARCHIVE_TYPE_7Z:
226 	case EV_ARCHIVE_TYPE_TAR:
227 	case EV_ARCHIVE_TYPE_RAR5:
228 		return libarchive_read_next_header (archive, error);
229 	}
230 
231 	return FALSE;
232 }
233 
234 const char *
ev_archive_get_entry_pathname(EvArchive * archive)235 ev_archive_get_entry_pathname (EvArchive *archive)
236 {
237 	g_return_val_if_fail (EV_IS_ARCHIVE (archive), NULL);
238 	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, NULL);
239 
240 	switch (archive->type) {
241 	case EV_ARCHIVE_TYPE_NONE:
242 		g_assert_not_reached ();
243 	case EV_ARCHIVE_TYPE_RAR:
244 		g_return_val_if_fail (archive->unarr != NULL, NULL);
245 		return ar_entry_get_name (archive->unarr);
246 	case EV_ARCHIVE_TYPE_ZIP:
247 	case EV_ARCHIVE_TYPE_7Z:
248 	case EV_ARCHIVE_TYPE_TAR:
249 	case EV_ARCHIVE_TYPE_RAR5:
250 		g_return_val_if_fail (archive->libar_entry != NULL, NULL);
251 		return archive_entry_pathname (archive->libar_entry);
252 	}
253 
254 	return NULL;
255 }
256 
257 gint64
ev_archive_get_entry_size(EvArchive * archive)258 ev_archive_get_entry_size (EvArchive *archive)
259 {
260 	g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1);
261 	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1);
262 
263 	switch (archive->type) {
264 	case EV_ARCHIVE_TYPE_RAR:
265 		g_return_val_if_fail (archive->unarr != NULL, -1);
266 		return ar_entry_get_size (archive->unarr);
267 	case EV_ARCHIVE_TYPE_NONE:
268 		g_assert_not_reached ();
269 	case EV_ARCHIVE_TYPE_ZIP:
270 	case EV_ARCHIVE_TYPE_7Z:
271 	case EV_ARCHIVE_TYPE_TAR:
272 	case EV_ARCHIVE_TYPE_RAR5:
273 		g_return_val_if_fail (archive->libar_entry != NULL, -1);
274 		return archive_entry_size (archive->libar_entry);
275 	}
276 
277 	return -1;
278 }
279 
280 gboolean
ev_archive_get_entry_is_encrypted(EvArchive * archive)281 ev_archive_get_entry_is_encrypted (EvArchive *archive)
282 {
283 	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
284 	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
285 
286 	switch (archive->type) {
287 	case EV_ARCHIVE_TYPE_RAR:
288 		g_return_val_if_fail (archive->unarr != NULL, FALSE);
289 		/* password-protected RAR is not even detected right now */
290 		return FALSE;
291 	case EV_ARCHIVE_TYPE_NONE:
292 		g_assert_not_reached ();
293 	case EV_ARCHIVE_TYPE_ZIP:
294 	case EV_ARCHIVE_TYPE_7Z:
295 	case EV_ARCHIVE_TYPE_TAR:
296 	case EV_ARCHIVE_TYPE_RAR5:
297 		g_return_val_if_fail (archive->libar_entry != NULL, -1);
298 		return archive_entry_is_encrypted (archive->libar_entry);
299 	}
300 
301 	return FALSE;
302 }
303 
304 gssize
ev_archive_read_data(EvArchive * archive,void * buf,gsize count,GError ** error)305 ev_archive_read_data (EvArchive *archive,
306 		      void      *buf,
307 		      gsize      count,
308 		      GError   **error)
309 {
310 	gssize r = -1;
311 
312 	g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1);
313 	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1);
314 
315 	switch (archive->type) {
316 	case EV_ARCHIVE_TYPE_RAR:
317 		g_return_val_if_fail (archive->unarr != NULL, -1);
318 		if (!ar_entry_uncompress (archive->unarr, buf, count)) {
319 			g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
320 					     "Failed to decompress RAR data");
321 			return -1;
322 		}
323 		r = count;
324 		break;
325 	case EV_ARCHIVE_TYPE_NONE:
326 		g_assert_not_reached ();
327 	case EV_ARCHIVE_TYPE_ZIP:
328 	case EV_ARCHIVE_TYPE_7Z:
329 	case EV_ARCHIVE_TYPE_TAR:
330 	case EV_ARCHIVE_TYPE_RAR5:
331 		g_return_val_if_fail (archive->libar_entry != NULL, -1);
332 		r = archive_read_data (archive->libar, buf, count);
333 		if (r < 0) {
334 			g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
335 				     "Failed to decompress data: %s", archive_error_string (archive->libar));
336 		}
337 		break;
338 	}
339 
340 	return r;
341 }
342 
343 void
ev_archive_reset(EvArchive * archive)344 ev_archive_reset (EvArchive *archive)
345 {
346 	g_return_if_fail (EV_IS_ARCHIVE (archive));
347 	g_return_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE);
348 
349 	switch (archive->type) {
350 	case EV_ARCHIVE_TYPE_RAR:
351 		g_clear_pointer (&archive->unarr, ar_close_archive);
352 		g_clear_pointer (&archive->unarr_stream, ar_close);
353 		break;
354 	case EV_ARCHIVE_TYPE_ZIP:
355 	case EV_ARCHIVE_TYPE_7Z:
356 	case EV_ARCHIVE_TYPE_TAR:
357 	case EV_ARCHIVE_TYPE_RAR5:
358 		g_clear_pointer (&archive->libar, archive_free);
359 		libarchive_set_archive_type (archive, archive->type);
360 		break;
361 	default:
362 		g_assert_not_reached ();
363 	}
364 }
365 
366 static void
ev_archive_init(EvArchive * archive)367 ev_archive_init (EvArchive *archive)
368 {
369 }
370