1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  File-Roller
5  *
6  *  Copyright (C) 2001 The Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <fcntl.h>
29 #include <glib.h>
30 #include "file-data.h"
31 #include "file-utils.h"
32 #include "glib-utils.h"
33 #include "fr-command.h"
34 #include "fr-command-cfile.h"
35 
36 
37 struct _FrCommandCFile
38 {
39 	FrCommand  parent_instance;
40 
41 	FrError    error;
42 };
43 
44 
G_DEFINE_TYPE(FrCommandCFile,fr_command_cfile,fr_command_get_type ())45 G_DEFINE_TYPE (FrCommandCFile, fr_command_cfile, fr_command_get_type ())
46 
47 
48 static char *
49 get_uncompressed_name_from_archive (FrCommand  *comm,
50 				    const char *archive)
51 {
52 	GFile        *file;
53 	GInputStream *stream;
54 	char         *filename = NULL;
55 
56 	if (! _g_mime_type_matches (FR_ARCHIVE (comm)->mime_type, "application/x-gzip"))
57 		return NULL;
58 
59 	file = g_file_new_for_path (archive);
60 
61 	stream = (GInputStream *) g_file_read (file, NULL, NULL);
62 	if (stream != NULL) {
63 		gboolean filename_present = TRUE;
64 		char     buffer[10];
65 
66 		if (g_input_stream_read (stream, buffer, 10, NULL, NULL) >= 0) {
67 			/* Check whether the FLG.FNAME is set */
68 			if (((unsigned char)(buffer[3]) & 0x08) != 0x08)
69 				filename_present = FALSE;
70 
71 			/* Check whether the FLG.FEXTRA is set */
72 			if (((unsigned char)(buffer[3]) & 0x04) == 0x04)
73 				filename_present = FALSE;
74 		}
75 
76 		if (filename_present) {
77 			GString *str = NULL;
78 
79 			str = g_string_new ("");
80 			while (g_input_stream_read (stream, buffer, 1, NULL, NULL) > 0) {
81 				if (buffer[0] == '\0') {
82 					filename = g_strdup (_g_path_get_basename (str->str));
83 #ifdef DEBUG
84 					g_message ("filename is: %s", filename);
85 #endif
86 					break;
87 				}
88 				g_string_append_c (str, buffer[0]);
89 			}
90 			g_string_free (str, TRUE);
91 		}
92 		g_object_unref (stream);
93 	}
94 	g_object_unref (file);
95 
96 	return filename;
97 }
98 
99 
100 static void
list__process_line(char * line,gpointer data)101 list__process_line (char     *line,
102 		    gpointer  data)
103 {
104 	FrCommand  *comm = FR_COMMAND (data);
105 	FileData   *fdata;
106 	char      **fields;
107 	GFile      *file;
108 	char       *filename;
109 
110 	fdata = file_data_new ();
111 
112 	fields = _g_str_split_line (line, 2);
113 	if (strcmp (fields[1], "-1") != 0)
114 		fdata->size = g_ascii_strtoull (fields[1], NULL, 10);
115 	g_strfreev (fields);
116 
117 	file = g_file_new_for_path (comm->filename);
118 
119 	if (fdata->size == 0)
120 		fdata->size = _g_file_get_file_size (file);
121 
122 	filename = get_uncompressed_name_from_archive (comm, comm->filename);
123 	if (filename == NULL)
124 		filename = _g_path_remove_first_extension (comm->filename);
125 
126 	fdata->full_path = g_strconcat ("/", _g_path_get_basename (filename), NULL);
127 	g_free (filename);
128 
129 	fdata->original_path = fdata->full_path + 1;
130 	fdata->link = NULL;
131 	fdata->modified = _g_file_get_file_mtime (file);
132 
133 	fdata->name = g_strdup (_g_path_get_basename (fdata->full_path));
134 	fdata->path = _g_path_remove_level (fdata->full_path);
135 
136 	if (*fdata->name == 0)
137 		file_data_free (fdata);
138 	else
139 		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
140 
141 	g_object_unref (file);
142 }
143 
144 
145 static gboolean
fr_command_cfile_list(FrCommand * comm)146 fr_command_cfile_list (FrCommand *comm)
147 {
148 	if (_g_mime_type_matches (FR_ARCHIVE (comm)->mime_type, "application/x-gzip")) {
149 		/* gzip let us known the uncompressed size */
150 
151 		fr_process_set_out_line_func (comm->process,
152 					      list__process_line,
153 					      comm);
154 
155 		fr_process_begin_command (comm->process, "gzip");
156 		fr_process_add_arg (comm->process, "-l");
157 		fr_process_add_arg (comm->process, "-q");
158 		fr_process_add_arg (comm->process, comm->filename);
159 		fr_process_end_command (comm->process);
160 	}
161 	else {
162 		/* ... other compressors do not support this feature so
163 		 * simply use the archive size, suboptimal but there is no
164 		 * alternative. */
165 
166 		FileData *fdata;
167 		char     *filename;
168 		GFile    *file;
169 
170 		fdata = file_data_new ();
171 
172 		filename = _g_path_remove_first_extension (comm->filename);
173 		fdata->full_path = g_strconcat ("/",
174 						_g_path_get_basename (filename),
175 						NULL);
176 		g_free (filename);
177 
178 		file = g_file_new_for_path (comm->filename);
179 
180 		fdata->original_path = fdata->full_path + 1;
181 		fdata->link = NULL;
182 		fdata->size = _g_file_get_file_size (file);
183 		fdata->modified = _g_file_get_file_mtime (file);
184 		fdata->name = g_strdup (_g_path_get_basename (fdata->full_path));
185 		fdata->path = _g_path_remove_level (fdata->full_path);
186 
187 		if (*fdata->name == 0)
188 			file_data_free (fdata);
189 		else
190 			fr_archive_add_file (FR_ARCHIVE (comm), fdata);
191 
192 		g_object_unref (file);
193 
194 		return FALSE;
195 	}
196 
197 	return TRUE;
198 }
199 
200 
201 static void
fr_command_cfile_add(FrCommand * comm,const char * from_file,GList * file_list,const char * base_dir,gboolean update,gboolean follow_links)202 fr_command_cfile_add (FrCommand  *comm,
203 		      const char *from_file,
204 		      GList      *file_list,
205 		      const char *base_dir,
206 		      gboolean    update,
207 		      gboolean    follow_links)
208 {
209 	FrArchive  *archive = FR_ARCHIVE (comm);
210 	const char *filename;
211 	char       *temp_dir;
212 	char       *temp_file;
213 	char       *compressed_filename;
214 
215 	if ((file_list == NULL) || (file_list->data == NULL))
216 		return;
217 
218 	/* copy file to the temp dir */
219 
220 	temp_dir = _g_path_get_temp_work_dir (NULL);
221 	filename = file_list->data;
222 	temp_file = g_strconcat (temp_dir, "/", filename, NULL);
223 
224 	fr_process_begin_command (comm->process, "cp");
225 	fr_process_set_working_dir (comm->process, base_dir);
226 	fr_process_add_arg (comm->process, "-f");
227 	fr_process_add_arg (comm->process, "--");
228 	fr_process_add_arg (comm->process, filename);
229 	fr_process_add_arg (comm->process, temp_file);
230 	fr_process_end_command (comm->process);
231 
232 	/**/
233 
234 	if (_g_mime_type_matches (archive->mime_type, "application/x-gzip")) {
235 		fr_process_begin_command (comm->process, "gzip");
236 		fr_process_set_working_dir (comm->process, temp_dir);
237 		fr_process_add_arg (comm->process, "--");
238 		fr_process_add_arg (comm->process, filename);
239 		fr_process_end_command (comm->process);
240 		compressed_filename = g_strconcat (filename, ".gz", NULL);
241 	}
242 	else if (_g_mime_type_matches (archive->mime_type, "application/x-brotli")) {
243 		fr_process_begin_command (comm->process, "brotli");
244 		fr_process_set_working_dir (comm->process, temp_dir);
245 		fr_process_add_arg (comm->process, "--");
246 		fr_process_add_arg (comm->process, filename);
247 		fr_process_end_command (comm->process);
248 		compressed_filename = g_strconcat (filename, ".br", NULL);
249 	}
250 	else if (_g_mime_type_matches (archive->mime_type, "application/x-bzip")) {
251 		fr_process_begin_command (comm->process, "bzip2");
252 		fr_process_set_working_dir (comm->process, temp_dir);
253 		fr_process_add_arg (comm->process, "--");
254 		fr_process_add_arg (comm->process, filename);
255 		fr_process_end_command (comm->process);
256 		compressed_filename = g_strconcat (filename, ".bz2", NULL);
257 	}
258 	else if (_g_mime_type_matches (archive->mime_type, "application/x-compress")) {
259 		fr_process_begin_command (comm->process, "compress");
260 		fr_process_set_working_dir (comm->process, temp_dir);
261 		fr_process_add_arg (comm->process, "-f");
262 		fr_process_add_arg (comm->process, filename);
263 		fr_process_end_command (comm->process);
264 		compressed_filename = g_strconcat (filename, ".Z", NULL);
265 	}
266 	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzip")) {
267 		fr_process_begin_command (comm->process, "lzip");
268 		fr_process_set_working_dir (comm->process, temp_dir);
269 		fr_process_add_arg (comm->process, "--");
270 		fr_process_add_arg (comm->process, filename);
271 		fr_process_end_command (comm->process);
272 		compressed_filename = g_strconcat (filename, ".lz", NULL);
273 	}
274 	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzma")) {
275 		fr_process_begin_command (comm->process, "lzma");
276 		fr_process_set_working_dir (comm->process, temp_dir);
277 		fr_process_add_arg (comm->process, "--");
278 		fr_process_add_arg (comm->process, filename);
279 		fr_process_end_command (comm->process);
280 		compressed_filename = g_strconcat (filename, ".lzma", NULL);
281 	}
282 	else if (_g_mime_type_matches (archive->mime_type, "application/x-xz")) {
283 		fr_process_begin_command (comm->process, "xz");
284 		fr_process_set_working_dir (comm->process, temp_dir);
285 		fr_process_add_arg (comm->process, "--");
286 		fr_process_add_arg (comm->process, filename);
287 		fr_process_end_command (comm->process);
288 		compressed_filename = g_strconcat (filename, ".xz", NULL);
289 	}
290 	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzop")) {
291 		fr_process_begin_command (comm->process, "lzop");
292 		fr_process_set_working_dir (comm->process, temp_dir);
293 		fr_process_add_arg (comm->process, "-fU");
294 		fr_process_add_arg (comm->process, "--no-stdin");
295 		fr_process_add_arg (comm->process, "--");
296 		fr_process_add_arg (comm->process, filename);
297 		fr_process_end_command (comm->process);
298 		compressed_filename = g_strconcat (filename, ".lzo", NULL);
299 	}
300 	else if (_g_mime_type_matches (archive->mime_type, "application/x-rzip")) {
301 		fr_process_begin_command (comm->process, "rzip");
302 		fr_process_set_working_dir (comm->process, temp_dir);
303 		fr_process_add_arg (comm->process, filename);
304 		fr_process_end_command (comm->process);
305 		compressed_filename = g_strconcat (filename, ".rz", NULL);
306 	}
307 	else if (_g_mime_type_matches (archive->mime_type, "application/x-lz4")) {
308 		compressed_filename = g_strconcat (filename, ".lz4", NULL);
309 		fr_process_begin_command (comm->process, "lz4");
310 		fr_process_set_working_dir (comm->process, temp_dir);
311 		fr_process_add_arg (comm->process, "-f");
312 		fr_process_add_arg (comm->process, "-z");
313 		fr_process_add_arg (comm->process, filename);
314 		fr_process_add_arg (comm->process, compressed_filename);
315 		fr_process_end_command (comm->process);
316 	}
317 	else if (_g_mime_type_matches (archive->mime_type, "application/zstd")) {
318 		fr_process_begin_command (comm->process, "zstd");
319 		fr_process_set_working_dir (comm->process, temp_dir);
320 		fr_process_add_arg (comm->process, "--");
321 		fr_process_add_arg (comm->process, filename);
322 		fr_process_end_command (comm->process);
323 		compressed_filename = g_strconcat (filename, ".zst", NULL);
324 	}
325 	else {
326 		g_warning ("Unhandled mime type: '%s'", archive->mime_type);
327 		g_warn_if_reached ();
328 		g_free (temp_file);
329 		g_free (temp_dir);
330 		return;
331 	}
332 
333       	/* copy compressed file to the dest dir */
334 
335 	fr_process_begin_command (comm->process, "cp");
336 	fr_process_set_working_dir (comm->process, temp_dir);
337 	fr_process_add_arg (comm->process, "-f");
338 	fr_process_add_arg (comm->process, "--");
339 	fr_process_add_arg (comm->process, compressed_filename);
340 	fr_process_add_arg (comm->process, comm->filename);
341 	fr_process_end_command (comm->process);
342 
343 	/* remove the temp dir */
344 
345 	fr_process_begin_command (comm->process, "rm");
346 	fr_process_set_sticky (comm->process, TRUE);
347 	fr_process_add_arg (comm->process, "-rf");
348 	fr_process_add_arg (comm->process, "--");
349 	fr_process_add_arg (comm->process, temp_dir);
350 	fr_process_end_command (comm->process);
351 
352 	g_free (compressed_filename);
353 	g_free (temp_file);
354 	g_free (temp_dir);
355 }
356 
357 
358 static void
fr_command_cfile_delete(FrCommand * comm,const char * from_file,GList * file_list)359 fr_command_cfile_delete (FrCommand  *comm,
360 			 const char *from_file,
361 			 GList      *file_list)
362 {
363 	/* never called */
364 }
365 
366 
367 static void
fr_command_cfile_extract(FrCommand * comm,const char * from_file,GList * file_list,const char * dest_dir,gboolean overwrite,gboolean skip_older,gboolean junk_paths)368 fr_command_cfile_extract (FrCommand  *comm,
369 			  const char *from_file,
370 			  GList      *file_list,
371 			  const char *dest_dir,
372 			  gboolean    overwrite,
373 			  gboolean    skip_older,
374 			  gboolean    junk_paths)
375 {
376 	FrArchive *archive = FR_ARCHIVE (comm);
377 	char      *temp_dir;
378 	char      *dest_file;
379 	char      *temp_file;
380 	char      *uncompr_file;
381 	char      *compr_file;
382 
383 	/* copy file to the temp dir, remove the already existing file first */
384 
385 	temp_dir = _g_path_get_temp_work_dir (NULL);
386 	temp_file = g_strconcat (temp_dir,
387 				 "/",
388 				 _g_path_get_basename (comm->filename),
389 				 NULL);
390 
391 	fr_process_begin_command (comm->process, "cp");
392 	fr_process_add_arg (comm->process, "-f");
393 	fr_process_add_arg (comm->process, comm->filename);
394 	fr_process_add_arg (comm->process, temp_file);
395 	fr_process_end_command (comm->process);
396 
397 	/* uncompress the file */
398 
399 	uncompr_file = _g_path_remove_first_extension (temp_file);
400 
401 	if (_g_mime_type_matches (archive->mime_type, "application/x-gzip")) {
402 		fr_process_begin_command (comm->process, "gzip");
403 		fr_process_set_working_dir (comm->process, temp_dir);
404 		fr_process_add_arg (comm->process, "-f");
405 		fr_process_add_arg (comm->process, "-d");
406 		fr_process_add_arg (comm->process, "-n");
407 		fr_process_add_arg (comm->process, temp_file);
408 		fr_process_end_command (comm->process);
409 	}
410 	else if (_g_mime_type_matches (archive->mime_type, "application/x-brotli")) {
411 		fr_process_begin_command (comm->process, "brotli");
412 		fr_process_set_working_dir (comm->process, temp_dir);
413 		fr_process_add_arg (comm->process, "-f");
414 		fr_process_add_arg (comm->process, "-d");
415 		fr_process_add_arg (comm->process, temp_file);
416 		fr_process_end_command (comm->process);
417 	}
418 	else if (_g_mime_type_matches (archive->mime_type, "application/x-bzip")) {
419 		fr_process_begin_command (comm->process, "bzip2");
420 		fr_process_set_working_dir (comm->process, temp_dir);
421 		fr_process_add_arg (comm->process, "-f");
422 		fr_process_add_arg (comm->process, "-d");
423 		fr_process_add_arg (comm->process, temp_file);
424 		fr_process_end_command (comm->process);
425 	}
426 	else if (_g_mime_type_matches (archive->mime_type, "application/x-compress")) {
427 		if (_g_program_is_in_path ("gzip")) {
428 			fr_process_begin_command (comm->process, "gzip");
429 			fr_process_add_arg (comm->process, "-d");
430 			fr_process_add_arg (comm->process, "-n");
431 		}
432 		else
433 			fr_process_begin_command (comm->process, "uncompress");
434 		fr_process_set_working_dir (comm->process, temp_dir);
435 		fr_process_add_arg (comm->process, "-f");
436 		fr_process_add_arg (comm->process, temp_file);
437 		fr_process_end_command (comm->process);
438 	}
439 	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzip")) {
440 		fr_process_begin_command (comm->process, "lzip");
441 		fr_process_set_working_dir (comm->process, temp_dir);
442 		fr_process_add_arg (comm->process, "-f");
443 		fr_process_add_arg (comm->process, "-d");
444 		fr_process_add_arg (comm->process, temp_file);
445 		fr_process_end_command (comm->process);
446 	}
447 	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzma")) {
448 		fr_process_begin_command (comm->process, "lzma");
449 		fr_process_set_working_dir (comm->process, temp_dir);
450 		fr_process_add_arg (comm->process, "-f");
451 		fr_process_add_arg (comm->process, "-d");
452 		fr_process_add_arg (comm->process, temp_file);
453 		fr_process_end_command (comm->process);
454 	}
455 	else if (_g_mime_type_matches (archive->mime_type, "application/x-xz")) {
456 		fr_process_begin_command (comm->process, "xz");
457 		fr_process_set_working_dir (comm->process, temp_dir);
458 		fr_process_add_arg (comm->process, "-f");
459 		fr_process_add_arg (comm->process, "-d");
460 		fr_process_add_arg (comm->process, temp_file);
461 		fr_process_end_command (comm->process);
462 	}
463 	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzop")) {
464 		fr_process_begin_command (comm->process, "lzop");
465 		fr_process_set_working_dir (comm->process, temp_dir);
466 		fr_process_add_arg (comm->process, "-d");
467 		fr_process_add_arg (comm->process, "-fU");
468 		fr_process_add_arg (comm->process, "--no-stdin");
469 		fr_process_add_arg (comm->process, temp_file);
470 		fr_process_end_command (comm->process);
471 	}
472 	else if (_g_mime_type_matches (archive->mime_type, "application/x-rzip")) {
473 		fr_process_begin_command (comm->process, "rzip");
474 		fr_process_set_working_dir (comm->process, temp_dir);
475 		fr_process_add_arg (comm->process, "-f");
476 		fr_process_add_arg (comm->process, "-d");
477 		fr_process_add_arg (comm->process, temp_file);
478 		fr_process_end_command (comm->process);
479 	}
480 	else if (_g_mime_type_matches (archive->mime_type, "application/x-lz4")) {
481 		fr_process_begin_command (comm->process, "lz4");
482 		fr_process_set_working_dir (comm->process, temp_dir);
483 		fr_process_add_arg (comm->process, "-f");
484 		fr_process_add_arg (comm->process, "-d");
485 		fr_process_add_arg (comm->process, temp_file);
486 		fr_process_add_arg (comm->process, uncompr_file);
487 		fr_process_end_command (comm->process);
488 	}
489 	else if (_g_mime_type_matches (archive->mime_type, "application/zstd")) {
490 		fr_process_begin_command (comm->process, "zstd");
491 		fr_process_set_working_dir (comm->process, temp_dir);
492 		fr_process_add_arg (comm->process, "-f");
493 		fr_process_add_arg (comm->process, "-d");
494 		fr_process_add_arg (comm->process, temp_file);
495 		fr_process_end_command (comm->process);
496 	}
497 
498 	/* copy uncompress file to the dest dir */
499 
500 	compr_file = get_uncompressed_name_from_archive (comm, comm->filename);
501 	if (compr_file == NULL)
502 		compr_file = _g_path_remove_first_extension (_g_path_get_basename (comm->filename));
503 	dest_file = g_strconcat (dest_dir,
504 				 "/",
505 				 compr_file,
506 				 NULL);
507 
508 	fr_process_begin_command (comm->process, "cp");
509 	fr_process_add_arg (comm->process, "-f");
510 	fr_process_add_arg (comm->process, uncompr_file);
511 	fr_process_add_arg (comm->process, dest_file);
512 	fr_process_end_command (comm->process);
513 
514 	/* remove the temp dir */
515 
516 	fr_process_begin_command (comm->process, "rm");
517 	fr_process_set_sticky (comm->process, TRUE);
518 	fr_process_add_arg (comm->process, "-rf");
519 	fr_process_add_arg (comm->process, temp_dir);
520 	fr_process_end_command (comm->process);
521 
522 	g_free (dest_file);
523 	g_free (compr_file);
524 	g_free (uncompr_file);
525 	g_free (temp_file);
526 	g_free (temp_dir);
527 }
528 
529 
530 const char *cfile_mime_type[] = { "application/x-gzip",
531 				  "application/x-brotli",
532 				  "application/x-bzip",
533 				  "application/x-compress",
534 				  "application/x-lz4",
535 				  "application/x-lzip",
536 				  "application/x-lzma",
537 				  "application/x-lzop",
538 				  "application/x-rzip",
539 				  "application/x-xz",
540 				  "application/zstd",
541 				  NULL };
542 
543 
544 static const char **
fr_command_cfile_get_mime_types(FrArchive * archive)545 fr_command_cfile_get_mime_types (FrArchive *archive)
546 {
547 	return cfile_mime_type;
548 }
549 
550 
551 static FrArchiveCap
fr_command_cfile_get_capabilities(FrArchive * archive,const char * mime_type,gboolean check_command)552 fr_command_cfile_get_capabilities (FrArchive  *archive,
553 			           const char *mime_type,
554 				   gboolean    check_command)
555 {
556 	FrArchiveCap capabilities;
557 
558 	capabilities = FR_ARCHIVE_CAN_DO_NOTHING;
559 	if (_g_mime_type_matches (mime_type, "application/x-gzip")) {
560 		if (_g_program_is_available ("gzip", check_command))
561 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
562 	}
563 	else if (_g_mime_type_matches (mime_type, "application/x-brotli")) {
564 		if (_g_program_is_available ("brotli", check_command))
565 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
566 	}
567 	else if (_g_mime_type_matches (mime_type, "application/x-bzip")) {
568 		if (_g_program_is_available ("bzip2", check_command))
569 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
570 	}
571 	else if (_g_mime_type_matches (mime_type, "application/x-compress")) {
572 		if (_g_program_is_available ("compress", check_command))
573 			capabilities |= FR_ARCHIVE_CAN_WRITE;
574 		if (_g_program_is_available ("uncompress", check_command) || _g_program_is_available ("gzip", check_command))
575 			capabilities |= FR_ARCHIVE_CAN_READ;
576 	}
577 	else if (_g_mime_type_matches (mime_type, "application/x-lzip")) {
578 		if (_g_program_is_available ("lzip", check_command))
579 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
580 	}
581 	else if (_g_mime_type_matches (mime_type, "application/x-lzma")) {
582 		if (_g_program_is_available ("lzma", check_command))
583 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
584 	}
585 	else if (_g_mime_type_matches (mime_type, "application/x-xz")) {
586 		if (_g_program_is_available ("xz", check_command))
587 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
588 	}
589 	else if (_g_mime_type_matches (mime_type, "application/x-lzop")) {
590 		if (_g_program_is_available ("lzop", check_command))
591 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
592 	}
593 	else if (_g_mime_type_matches (mime_type, "application/x-rzip") ||
594 		 _g_mime_type_matches (mime_type, "application/x-rzip-compressed-tar")) {
595 		if (_g_program_is_available ("rzip", check_command))
596 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
597 	}
598 	else if (_g_mime_type_matches (mime_type, "application/x-lz4")) {
599 		if (_g_program_is_available ("lz4", check_command))
600 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
601 	}
602 	else if (_g_mime_type_matches (mime_type, "application/zstd")) {
603 		if (_g_program_is_available ("zstd", check_command))
604 			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
605 	}
606 	return capabilities;
607 }
608 
609 
610 static const char *
fr_command_cfile_get_packages(FrArchive * archive,const char * mime_type)611 fr_command_cfile_get_packages (FrArchive  *archive,
612 			       const char *mime_type)
613 {
614 	if (_g_mime_type_matches (mime_type, "application/x-gzip"))
615 		return PACKAGES ("gzip");
616 	else if (_g_mime_type_matches (mime_type, "application/x-brotli"))
617 		return PACKAGES ("brotli");
618 	else if (_g_mime_type_matches (mime_type, "application/x-bzip"))
619 		return PACKAGES ("bzip2");
620 	else if (_g_mime_type_matches (mime_type, "application/x-compress"))
621 		return PACKAGES ("ncompress");
622 	else if (_g_mime_type_matches (mime_type, "application/x-lzip"))
623 		return PACKAGES ("lzip");
624 	else if (_g_mime_type_matches (mime_type, "application/x-lzma"))
625 		return PACKAGES ("lzma");
626 	else if (_g_mime_type_matches (mime_type, "application/x-xz"))
627 		return PACKAGES ("xz");
628 	else if (_g_mime_type_matches (mime_type, "application/x-lzop"))
629 		return PACKAGES ("lzop");
630 	else if (_g_mime_type_matches (mime_type, "application/x-rzip"))
631 		return PACKAGES ("rzip");
632 	else if (_g_mime_type_matches (mime_type, "application/x-lz4"))
633 		return PACKAGES ("lz4");
634 	else if (_g_mime_type_matches (mime_type, "application/zstd"))
635 		return PACKAGES ("zstd");
636 
637 	return NULL;
638 }
639 
640 
641 static void
fr_command_cfile_finalize(GObject * object)642 fr_command_cfile_finalize (GObject *object)
643 {
644         g_return_if_fail (object != NULL);
645         g_return_if_fail (FR_IS_COMMAND_CFILE (object));
646 
647 	/* Chain up */
648         if (G_OBJECT_CLASS (fr_command_cfile_parent_class)->finalize)
649                 G_OBJECT_CLASS (fr_command_cfile_parent_class)->finalize (object);
650 }
651 
652 
653 static void
fr_command_cfile_class_init(FrCommandCFileClass * klass)654 fr_command_cfile_class_init (FrCommandCFileClass *klass)
655 {
656         GObjectClass   *gobject_class;
657         FrArchiveClass *archive_class;
658         FrCommandClass *command_class;
659 
660         fr_command_cfile_parent_class = g_type_class_peek_parent (klass);
661 
662 	gobject_class = G_OBJECT_CLASS (klass);
663         gobject_class->finalize = fr_command_cfile_finalize;
664 
665 	archive_class = FR_ARCHIVE_CLASS (klass);
666 	archive_class->get_mime_types   = fr_command_cfile_get_mime_types;
667 	archive_class->get_capabilities = fr_command_cfile_get_capabilities;
668 	archive_class->get_packages     = fr_command_cfile_get_packages;
669 
670         command_class = FR_COMMAND_CLASS (klass);
671         command_class->list             = fr_command_cfile_list;
672 	command_class->add              = fr_command_cfile_add;
673 	command_class->delete           = fr_command_cfile_delete;
674 	command_class->extract          = fr_command_cfile_extract;
675 }
676 
677 
678 static void
fr_command_cfile_init(FrCommandCFile * self)679 fr_command_cfile_init (FrCommandCFile *self)
680 {
681 	FrArchive *base = FR_ARCHIVE (self);
682 
683 	base->propAddCanUpdate             = TRUE;
684 	base->propAddCanReplace            = TRUE;
685 	base->propAddCanStoreLinks         = FALSE;
686 	base->propExtractCanAvoidOverwrite = FALSE;
687 	base->propExtractCanSkipOlder      = FALSE;
688 	base->propExtractCanJunkPaths      = FALSE;
689 	base->propPassword                 = FALSE;
690 	base->propTest                     = FALSE;
691 }
692