1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * Engrampa
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, write to the Free Software
20 * Foundation, Inc., 59 Temple Street #330, Boston, MA 02110-1301, USA.
21 */
22
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
30 #include <glib.h>
31
32 #include "file-data.h"
33 #include "file-utils.h"
34 #include "glib-utils.h"
35 #include "fr-command.h"
36 #include "fr-command-cfile.h"
37
38
39 /* Parent Class */
40
41 static FrCommandClass *parent_class = NULL;
42
43
44 static char *
get_uncompressed_name_from_archive(FrCommand * comm,const char * archive)45 get_uncompressed_name_from_archive (FrCommand *comm,
46 const char *archive)
47 {
48 GFile *file;
49 GInputStream *stream;
50 char *filename = NULL;
51
52 if (! is_mime_type (comm->mime_type, "application/gzip"))
53 return NULL;
54
55 file = g_file_new_for_path (archive);
56
57 stream = (GInputStream *) g_file_read (file, NULL, NULL);
58 if (stream != NULL) {
59 gboolean filename_present = TRUE;
60 char buffer[10];
61
62 if (g_input_stream_read (stream, buffer, 10, NULL, NULL) >= 0) {
63 /* Check whether the FLG.FNAME is set */
64 if (((unsigned char)(buffer[3]) & 0x08) != 0x08)
65 filename_present = FALSE;
66
67 /* Check whether the FLG.FEXTRA is set */
68 if (((unsigned char)(buffer[3]) & 0x04) == 0x04)
69 filename_present = FALSE;
70 }
71
72 if (filename_present) {
73 GString *str = NULL;
74
75 str = g_string_new ("");
76 while (g_input_stream_read (stream, buffer, 1, NULL, NULL) > 0) {
77 if (buffer[0] == '\0') {
78 filename = g_strdup (file_name_from_path (str->str));
79 #ifdef DEBUG
80 g_message ("filename is: %s", filename);
81 #endif
82 break;
83 }
84 g_string_append_c (str, buffer[0]);
85 }
86 g_string_free (str, TRUE);
87 }
88 g_object_unref (stream);
89 }
90 g_object_unref (file);
91
92 return filename;
93 }
94
95
96 static void
list__process_line(char * line,gpointer data)97 list__process_line (char *line,
98 gpointer data)
99 {
100 FrCommand *comm = FR_COMMAND (data);
101 FileData *fdata;
102 char **fields;
103 char *filename;
104
105 fdata = file_data_new ();
106
107 fields = split_line (line, 2);
108 if (strcmp (fields[1], "-1") != 0)
109 fdata->size = g_ascii_strtoull (fields[1], NULL, 10);
110 g_strfreev (fields);
111
112 if (fdata->size == 0)
113 fdata->size = get_file_size (comm->filename);
114
115 filename = get_uncompressed_name_from_archive (comm, comm->filename);
116 if (filename == NULL)
117 filename = remove_extension_from_path (comm->filename);
118
119 fdata->full_path = g_strconcat ("/",
120 file_name_from_path (filename),
121 NULL);
122 g_free (filename);
123
124 fdata->original_path = fdata->full_path + 1;
125 fdata->link = NULL;
126 fdata->modified = get_file_mtime_for_path (comm->filename);
127
128 fdata->name = g_strdup (file_name_from_path (fdata->full_path));
129 fdata->path = remove_level_from_path (fdata->full_path);
130
131 if (*fdata->name == 0)
132 file_data_free (fdata);
133 else
134 fr_command_add_file (comm, fdata);
135 }
136
137
138 static void
fr_command_cfile_list(FrCommand * comm)139 fr_command_cfile_list (FrCommand *comm)
140 {
141 FrCommandCFile *comm_cfile = FR_COMMAND_CFILE (comm);
142
143 if (is_mime_type (comm->mime_type, "application/gzip")) {
144 /* gzip let us known the uncompressed size */
145
146 fr_process_set_out_line_func (FR_COMMAND (comm)->process,
147 list__process_line,
148 comm);
149
150 fr_process_begin_command (comm->process, "gzip");
151 fr_process_add_arg (comm->process, "-l");
152 fr_process_add_arg (comm->process, "-q");
153 fr_process_add_arg (comm->process, comm->filename);
154 fr_process_end_command (comm->process);
155 fr_process_start (comm->process);
156 }
157 else {
158 /* ... other compressors do not support this feature so
159 * simply use the archive size, suboptimal but there is no
160 * alternative. */
161
162 FileData *fdata;
163 char *filename;
164
165 fdata = file_data_new ();
166
167 filename = remove_extension_from_path (comm->filename);
168 fdata->full_path = g_strconcat ("/",
169 file_name_from_path (filename),
170 NULL);
171 g_free (filename);
172
173 fdata->original_path = fdata->full_path + 1;
174 fdata->link = NULL;
175 fdata->size = get_file_size_for_path (comm->filename);
176 fdata->modified = get_file_mtime_for_path (comm->filename);
177
178 fdata->name = g_strdup (file_name_from_path (fdata->full_path));
179 fdata->path = remove_level_from_path (fdata->full_path);
180
181 if (*fdata->name == 0)
182 file_data_free (fdata);
183 else
184 fr_command_add_file (comm, fdata);
185
186 comm_cfile->error.type = FR_PROC_ERROR_NONE;
187 comm_cfile->error.status = 0;
188 g_signal_emit_by_name (G_OBJECT (comm),
189 "done",
190 comm->action,
191 &comm_cfile->error);
192 }
193 }
194
195
196 static void
fr_command_cfile_add(FrCommand * comm,const char * from_file,GList * file_list,const char * base_dir,gboolean update,gboolean recursive)197 fr_command_cfile_add (FrCommand *comm,
198 const char *from_file,
199 GList *file_list,
200 const char *base_dir,
201 gboolean update,
202 gboolean recursive)
203 {
204 const char *filename = NULL;
205 char *temp_dir = NULL;
206 char *temp_file = NULL;
207 char *compressed_filename = NULL;
208
209 if ((file_list == NULL) || (file_list->data == NULL))
210 return;
211
212 /* copy file to the temp dir */
213
214 temp_dir = get_temp_work_dir (NULL);
215 filename = file_list->data;
216 temp_file = g_strconcat (temp_dir, "/", filename, NULL);
217
218 fr_process_begin_command (comm->process, "cp");
219 fr_process_set_working_dir (comm->process, base_dir);
220 fr_process_add_arg (comm->process, "-f");
221 fr_process_add_arg (comm->process, "--");
222 fr_process_add_arg (comm->process, filename);
223 fr_process_add_arg (comm->process, temp_file);
224 fr_process_end_command (comm->process);
225
226 /**/
227
228 if (is_mime_type (comm->mime_type, "application/gzip")) {
229 fr_process_begin_command (comm->process, "gzip");
230 fr_process_set_working_dir (comm->process, temp_dir);
231 fr_process_add_arg (comm->process, "--");
232 fr_process_add_arg (comm->process, filename);
233 fr_process_end_command (comm->process);
234 compressed_filename = g_strconcat (filename, ".gz", NULL);
235 }
236 else if (is_mime_type (comm->mime_type, "application/x-bzip")) {
237 fr_process_begin_command (comm->process, "bzip2");
238 fr_process_set_working_dir (comm->process, temp_dir);
239 fr_process_add_arg (comm->process, "--");
240 fr_process_add_arg (comm->process, filename);
241 fr_process_end_command (comm->process);
242 compressed_filename = g_strconcat (filename, ".bz2", NULL);
243 }
244 else if (is_mime_type (comm->mime_type, "application/x-compress")) {
245 fr_process_begin_command (comm->process, "compress");
246 fr_process_set_working_dir (comm->process, temp_dir);
247 fr_process_add_arg (comm->process, "-f");
248 fr_process_add_arg (comm->process, filename);
249 fr_process_end_command (comm->process);
250 compressed_filename = g_strconcat (filename, ".Z", NULL);
251 }
252 else if (is_mime_type (comm->mime_type, "application/x-lzip")) {
253 fr_process_begin_command (comm->process, "lzip");
254 fr_process_set_working_dir (comm->process, temp_dir);
255 fr_process_add_arg (comm->process, "--");
256 fr_process_add_arg (comm->process, filename);
257 fr_process_end_command (comm->process);
258 compressed_filename = g_strconcat (filename, ".lz", NULL);
259 }
260 else if (is_mime_type (comm->mime_type, "application/x-lzma")) {
261 fr_process_begin_command (comm->process, "lzma");
262 fr_process_set_working_dir (comm->process, temp_dir);
263 fr_process_add_arg (comm->process, "--");
264 fr_process_add_arg (comm->process, filename);
265 fr_process_end_command (comm->process);
266 compressed_filename = g_strconcat (filename, ".lzma", NULL);
267 }
268 else if (is_mime_type (comm->mime_type, "application/x-xz")) {
269 fr_process_begin_command (comm->process, "xz");
270 fr_process_set_working_dir (comm->process, temp_dir);
271 fr_process_add_arg (comm->process, "--");
272 fr_process_add_arg (comm->process, filename);
273 fr_process_end_command (comm->process);
274 compressed_filename = g_strconcat (filename, ".xz", NULL);
275 }
276 else if (is_mime_type (comm->mime_type, "application/x-zstd")) {
277 fr_process_begin_command (comm->process, "zstd");
278 fr_process_set_working_dir (comm->process, temp_dir);
279 fr_process_add_arg (comm->process, "--");
280 fr_process_add_arg (comm->process, filename);
281 fr_process_end_command (comm->process);
282 compressed_filename = g_strconcat (filename, ".zst", NULL);
283 }
284 else if (is_mime_type (comm->mime_type, "application/x-lzop")) {
285 fr_process_begin_command (comm->process, "lzop");
286 fr_process_set_working_dir (comm->process, temp_dir);
287 fr_process_add_arg (comm->process, "-fU");
288 fr_process_add_arg (comm->process, "--no-stdin");
289 fr_process_add_arg (comm->process, "--");
290 fr_process_add_arg (comm->process, filename);
291 fr_process_end_command (comm->process);
292 compressed_filename = g_strconcat (filename, ".lzo", NULL);
293 }
294 else if (is_mime_type (comm->mime_type, "application/x-rzip")) {
295 fr_process_begin_command (comm->process, "rzip");
296 fr_process_set_working_dir (comm->process, temp_dir);
297 fr_process_add_arg (comm->process, filename);
298 fr_process_end_command (comm->process);
299 compressed_filename = g_strconcat (filename, ".rz", NULL);
300 }
301
302 /* copy compressed file to the dest dir */
303
304 fr_process_begin_command (comm->process, "cp");
305 fr_process_set_working_dir (comm->process, temp_dir);
306 fr_process_add_arg (comm->process, "-f");
307 fr_process_add_arg (comm->process, "--");
308 fr_process_add_arg (comm->process, compressed_filename);
309 fr_process_add_arg (comm->process, comm->filename);
310 fr_process_end_command (comm->process);
311
312 /* remove the temp dir */
313
314 fr_process_begin_command (comm->process, "rm");
315 fr_process_set_sticky (comm->process, TRUE);
316 fr_process_add_arg (comm->process, "-rf");
317 fr_process_add_arg (comm->process, "--");
318 fr_process_add_arg (comm->process, temp_dir);
319 fr_process_end_command (comm->process);
320
321 g_free (compressed_filename);
322 g_free (temp_file);
323 g_free (temp_dir);
324 }
325
326
327 static void
fr_command_cfile_delete(FrCommand * comm,const char * from_file,GList * file_list)328 fr_command_cfile_delete (FrCommand *comm,
329 const char *from_file,
330 GList *file_list)
331 {
332 /* never called */
333 }
334
335
336 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)337 fr_command_cfile_extract (FrCommand *comm,
338 const char *from_file,
339 GList *file_list,
340 const char *dest_dir,
341 gboolean overwrite,
342 gboolean skip_older,
343 gboolean junk_paths)
344 {
345 char *temp_dir;
346 char *dest_file;
347 char *temp_file;
348 char *uncompr_file;
349 char *compr_file;
350
351 /* copy file to the temp dir, remove the already existing file first */
352
353 temp_dir = get_temp_work_dir (NULL);
354 temp_file = g_strconcat (temp_dir,
355 "/",
356 file_name_from_path (comm->filename),
357 NULL);
358
359 fr_process_begin_command (comm->process, "cp");
360 fr_process_add_arg (comm->process, "-f");
361 fr_process_add_arg (comm->process, comm->filename);
362 fr_process_add_arg (comm->process, temp_file);
363 fr_process_end_command (comm->process);
364
365 /* uncompress the file */
366
367 if (is_mime_type (comm->mime_type, "application/gzip")) {
368 fr_process_begin_command (comm->process, "gzip");
369 fr_process_add_arg (comm->process, "-f");
370 fr_process_add_arg (comm->process, "-d");
371 fr_process_add_arg (comm->process, "-n");
372 fr_process_add_arg (comm->process, temp_file);
373 fr_process_end_command (comm->process);
374 }
375 else if (is_mime_type (comm->mime_type, "application/x-bzip")) {
376 fr_process_begin_command (comm->process, "bzip2");
377 fr_process_add_arg (comm->process, "-f");
378 fr_process_add_arg (comm->process, "-d");
379 fr_process_add_arg (comm->process, temp_file);
380 fr_process_end_command (comm->process);
381 }
382 else if (is_mime_type (comm->mime_type, "application/x-compress")) {
383 if (is_program_in_path ("gzip")) {
384 fr_process_begin_command (comm->process, "gzip");
385 fr_process_add_arg (comm->process, "-d");
386 fr_process_add_arg (comm->process, "-n");
387 }
388 else
389 fr_process_begin_command (comm->process, "uncompress");
390 fr_process_add_arg (comm->process, "-f");
391 fr_process_add_arg (comm->process, temp_file);
392 fr_process_end_command (comm->process);
393 }
394 else if (is_mime_type (comm->mime_type, "application/x-lzip")) {
395 fr_process_begin_command (comm->process, "lzip");
396 fr_process_add_arg (comm->process, "-f");
397 fr_process_add_arg (comm->process, "-d");
398 fr_process_add_arg (comm->process, temp_file);
399 fr_process_end_command (comm->process);
400 }
401 else if (is_mime_type (comm->mime_type, "application/x-lzma")) {
402 fr_process_begin_command (comm->process, "lzma");
403 fr_process_add_arg (comm->process, "-f");
404 fr_process_add_arg (comm->process, "-d");
405 fr_process_add_arg (comm->process, temp_file);
406 fr_process_end_command (comm->process);
407 }
408 else if (is_mime_type (comm->mime_type, "application/x-xz")) {
409 fr_process_begin_command (comm->process, "xz");
410 fr_process_add_arg (comm->process, "-f");
411 fr_process_add_arg (comm->process, "-d");
412 fr_process_add_arg (comm->process, temp_file);
413 fr_process_end_command (comm->process);
414 }
415 else if (is_mime_type (comm->mime_type, "application/x-zstd")) {
416 fr_process_begin_command (comm->process, "zstd");
417 fr_process_add_arg (comm->process, "-f");
418 fr_process_add_arg (comm->process, "-d");
419 fr_process_add_arg (comm->process, temp_file);
420 fr_process_end_command (comm->process);
421 }
422 else if (is_mime_type (comm->mime_type, "application/x-lzop")) {
423 fr_process_begin_command (comm->process, "lzop");
424 fr_process_set_working_dir (comm->process, temp_dir);
425 fr_process_add_arg (comm->process, "-d");
426 fr_process_add_arg (comm->process, "-fU");
427 fr_process_add_arg (comm->process, "--no-stdin");
428 fr_process_add_arg (comm->process, temp_file);
429 fr_process_end_command (comm->process);
430 }
431 else if (is_mime_type (comm->mime_type, "application/x-rzip")) {
432 fr_process_begin_command (comm->process, "rzip");
433 fr_process_add_arg (comm->process, "-f");
434 fr_process_add_arg (comm->process, "-d");
435 fr_process_add_arg (comm->process, temp_file);
436 fr_process_end_command (comm->process);
437 }
438
439 /* copy uncompress file to the dest dir */
440
441 uncompr_file = remove_extension_from_path (temp_file);
442
443 compr_file = get_uncompressed_name_from_archive (comm, comm->filename);
444 if (compr_file == NULL)
445 compr_file = remove_extension_from_path (file_name_from_path (comm->filename));
446 dest_file = g_strconcat (dest_dir,
447 "/",
448 compr_file,
449 NULL);
450
451 fr_process_begin_command (comm->process, "cp");
452 fr_process_add_arg (comm->process, "-f");
453 fr_process_add_arg (comm->process, uncompr_file);
454 fr_process_add_arg (comm->process, dest_file);
455 fr_process_end_command (comm->process);
456
457 /* remove the temp dir */
458
459 fr_process_begin_command (comm->process, "rm");
460 fr_process_set_sticky (comm->process, TRUE);
461 fr_process_add_arg (comm->process, "-rf");
462 fr_process_add_arg (comm->process, temp_dir);
463 fr_process_end_command (comm->process);
464
465 g_free (dest_file);
466 g_free (compr_file);
467 g_free (uncompr_file);
468 g_free (temp_file);
469 g_free (temp_dir);
470 }
471
472
473 const char *cfile_mime_type[] = { "application/gzip",
474 "application/x-bzip",
475 "application/x-compress",
476 "application/x-lzip",
477 "application/x-lzma",
478 "application/x-lzop",
479 "application/x-rzip",
480 "application/x-xz",
481 "application/x-zstd",
482 NULL };
483
484
485 static const char **
fr_command_cfile_get_mime_types(FrCommand * comm)486 fr_command_cfile_get_mime_types (FrCommand *comm)
487 {
488 return cfile_mime_type;
489 }
490
491
492 static FrCommandCap
fr_command_cfile_get_capabilities(FrCommand * comm,const char * mime_type,gboolean check_command)493 fr_command_cfile_get_capabilities (FrCommand *comm,
494 const char *mime_type,
495 gboolean check_command)
496 {
497 FrCommandCap capabilities;
498
499 capabilities = FR_COMMAND_CAN_DO_NOTHING;
500 if (is_mime_type (mime_type, "application/gzip")) {
501 if (is_program_available ("gzip", check_command))
502 capabilities |= FR_COMMAND_CAN_READ_WRITE;
503 }
504 else if (is_mime_type (mime_type, "application/x-bzip")) {
505 if (is_program_available ("bzip2", check_command))
506 capabilities |= FR_COMMAND_CAN_READ_WRITE;
507 }
508 else if (is_mime_type (mime_type, "application/x-compress")) {
509 if (is_program_available ("compress", check_command))
510 capabilities |= FR_COMMAND_CAN_WRITE;
511 if (is_program_available ("uncompress", check_command) || is_program_available ("gzip", check_command))
512 capabilities |= FR_COMMAND_CAN_READ;
513 }
514 else if (is_mime_type (mime_type, "application/x-lzip")) {
515 if (is_program_available ("lzip", check_command))
516 capabilities |= FR_COMMAND_CAN_READ_WRITE;
517 }
518 else if (is_mime_type (mime_type, "application/x-lzma")) {
519 if (is_program_available ("lzma", check_command))
520 capabilities |= FR_COMMAND_CAN_READ_WRITE;
521 }
522 else if (is_mime_type (mime_type, "application/x-xz")) {
523 if (is_program_available ("xz", check_command))
524 capabilities |= FR_COMMAND_CAN_READ_WRITE;
525 }
526 else if (is_mime_type (mime_type, "application/x-zstd")) {
527 if (is_program_available ("zstd", check_command))
528 capabilities |= FR_COMMAND_CAN_READ_WRITE;
529 }
530 else if (is_mime_type (mime_type, "application/x-lzop")) {
531 if (is_program_available ("lzop", check_command))
532 capabilities |= FR_COMMAND_CAN_READ_WRITE;
533 }
534 else if (is_mime_type (mime_type, "application/x-rzip")) {
535 if (is_program_available ("rzip", check_command))
536 capabilities |= FR_COMMAND_CAN_READ_WRITE;
537 }
538
539 return capabilities;
540 }
541
542
543 static void
fr_command_cfile_finalize(GObject * object)544 fr_command_cfile_finalize (GObject *object)
545 {
546 g_return_if_fail (object != NULL);
547 g_return_if_fail (FR_IS_COMMAND_CFILE (object));
548
549 /* Chain up */
550 if (G_OBJECT_CLASS (parent_class)->finalize)
551 G_OBJECT_CLASS (parent_class)->finalize (object);
552 }
553
554
555 static const char *
fr_command_cfile_get_packages(FrCommand * comm,const char * mime_type)556 fr_command_cfile_get_packages (FrCommand *comm,
557 const char *mime_type)
558 {
559 if (is_mime_type (mime_type, "application/gzip"))
560 return PACKAGES ("gzip");
561 else if (is_mime_type (mime_type, "application/x-bzip"))
562 return PACKAGES ("bzip2");
563 else if (is_mime_type (mime_type, "application/x-compress"))
564 return PACKAGES ("ncompress");
565 else if (is_mime_type (mime_type, "application/x-lzip"))
566 return PACKAGES ("lzip");
567 else if (is_mime_type (mime_type, "application/x-lzma"))
568 return PACKAGES ("lzma");
569 else if (is_mime_type (mime_type, "application/x-xz"))
570 return PACKAGES ("xz");
571 else if (is_mime_type (mime_type, "application/x-zstd"))
572 return PACKAGES ("zstd");
573 else if (is_mime_type (mime_type, "application/x-lzop"))
574 return PACKAGES ("lzop");
575 else if (is_mime_type (mime_type, "application/x-rzip"))
576 return PACKAGES ("rzip");
577
578 return NULL;
579 }
580
581
582 static void
fr_command_cfile_class_init(FrCommandCFileClass * class)583 fr_command_cfile_class_init (FrCommandCFileClass *class)
584 {
585 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
586 FrCommandClass *afc;
587
588 parent_class = g_type_class_peek_parent (class);
589 afc = (FrCommandClass*) class;
590
591 gobject_class->finalize = fr_command_cfile_finalize;
592
593 afc->list = fr_command_cfile_list;
594 afc->add = fr_command_cfile_add;
595 afc->delete_ = fr_command_cfile_delete;
596 afc->extract = fr_command_cfile_extract;
597 afc->get_mime_types = fr_command_cfile_get_mime_types;
598 afc->get_capabilities = fr_command_cfile_get_capabilities;
599 afc->get_packages = fr_command_cfile_get_packages;
600 }
601
602
603 static void
fr_command_cfile_init(FrCommand * comm)604 fr_command_cfile_init (FrCommand *comm)
605 {
606 comm->propAddCanUpdate = TRUE;
607 comm->propAddCanReplace = TRUE;
608 comm->propExtractCanAvoidOverwrite = FALSE;
609 comm->propExtractCanSkipOlder = FALSE;
610 comm->propExtractCanJunkPaths = FALSE;
611 comm->propPassword = FALSE;
612 comm->propTest = FALSE;
613 }
614
615
616 GType
fr_command_cfile_get_type()617 fr_command_cfile_get_type ()
618 {
619 static GType type = 0;
620
621 if (! type) {
622 GTypeInfo type_info = {
623 sizeof (FrCommandCFileClass),
624 NULL,
625 NULL,
626 (GClassInitFunc) fr_command_cfile_class_init,
627 NULL,
628 NULL,
629 sizeof (FrCommandCFile),
630 0,
631 (GInstanceInitFunc) fr_command_cfile_init
632 };
633
634 type = g_type_register_static (FR_TYPE_COMMAND,
635 "FRCommandCFile",
636 &type_info,
637 0);
638 }
639
640 return type;
641 }
642