1 /*
2 * Copyright (C) 2008 Giuseppe Torelli - <colossus73@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA.
18 */
19
20 #include <string.h>
21 #include "rar.h"
22 #include "date_utils.h"
23 #include "interface.h"
24 #include "main.h"
25 #include "string_utils.h"
26 #include "support.h"
27 #include "window.h"
28
29 int rar_version;
30
31 static gboolean header_line, data_line, fname_line, last_line;
32
xa_rar_check_version(gchar * path)33 void xa_rar_check_version (gchar *path)
34 {
35 gchar *output, *id;
36 gchar version;
37
38 g_spawn_command_line_sync(path, &output, NULL, NULL, NULL);
39
40 id = strstr(output, "\nRAR ");
41
42 if (!id)
43 id = strstr(output, "\nUNRAR ");
44
45 if (id)
46 {
47 version = *(strchr(id, ' ') + 1);
48
49 if (version > '1' && version <= '9')
50 rar_version = version - '0';
51 }
52
53 g_free(output);
54 }
55
xa_rar_ask(XArchive * archive)56 void xa_rar_ask (XArchive *archive)
57 {
58 archive->can_test = TRUE;
59 archive->can_extract = TRUE;
60 archive->can_add = archiver[archive->type].is_compressor;
61 archive->can_delete = archiver[archive->type].is_compressor;
62 archive->can_sfx = archiver[archive->type].is_compressor;
63 archive->can_password = archiver[archive->type].is_compressor;
64 archive->can_full_path[0] = TRUE;
65 archive->can_full_path[1] = archiver[archive->type].is_compressor;
66 archive->can_touch = TRUE;
67 archive->can_overwrite = TRUE;
68 archive->can_update[0] = TRUE;
69 archive->can_update[1] = archiver[archive->type].is_compressor;
70 archive->can_freshen[0] = TRUE;
71 archive->can_freshen[1] = archiver[archive->type].is_compressor;
72 archive->can_move = archiver[archive->type].is_compressor;
73 archive->can_solid = archiver[archive->type].is_compressor;
74 }
75
xa_rar_password_str(XArchive * archive)76 static gchar *xa_rar_password_str (XArchive *archive)
77 {
78 if (archive->password)
79 return g_strconcat(" -p", archive->password, NULL);
80 else
81 return g_strdup("");
82 }
83
xa_rar_parse_output(gchar * line,XArchive * archive)84 static void xa_rar_parse_output (gchar *line, XArchive *archive)
85 {
86 XEntry *entry;
87 gpointer item[9];
88 unsigned short int i = 0;
89 unsigned int linesize,n,a;
90 gboolean dir = FALSE;
91 static gboolean encrypted;
92 static gchar *filename;
93
94 if (last_line)
95 return;
96
97 if (!data_line)
98 {
99 if (!header_line)
100 {
101 if ((strncmp(line, "Solid ", 6) == 0 || strncmp(line, "SFX ", 4) == 0 ||
102 strncmp(line, "Volume ", 7) == 0 || strncmp(line, "Archive ", 8) == 0)
103 && strstr(line, archive->path[0]))
104 {
105 header_line = TRUE;
106
107 if (archive->comment)
108 {
109 if (archive->comment->len > 2)
110 {
111 archive->has_comment = TRUE;
112 archive->comment = g_string_truncate(archive->comment, archive->comment->len - 2);
113 archive->comment = g_string_erase(archive->comment, 0, 1);
114 }
115 else
116 {
117 g_string_free(archive->comment, TRUE);
118 archive->comment = NULL;
119 }
120 }
121 }
122 else
123 {
124 if (!archive->comment)
125 archive->comment = g_string_new("");
126
127 archive->comment = g_string_append(archive->comment, line);
128 }
129 return;
130 }
131 if (line[0] == '-')
132 {
133 data_line = TRUE;
134 return;
135 }
136 return;
137 }
138
139 if (!fname_line)
140 {
141 encrypted = FALSE;
142 linesize = strlen(line);
143 if(line[0] == '*')
144 {
145 archive->has_password = TRUE;
146 encrypted = TRUE;
147 }
148 else if (line[0] == '-')
149 {
150 last_line = TRUE;
151 return;
152 }
153 else if (line[0] != ' ')
154 return;
155 line[linesize - 1] = '\0';
156 filename = g_strdup(line+1);
157 fname_line = TRUE;
158 }
159 else
160 {
161 linesize = strlen(line);
162 /* Size */
163 for(n=0; n < linesize && line[n] == ' '; n++);
164 a = n;
165 for(; n < linesize && line[n] != ' '; n++);
166 line[n]='\0';
167 item[i] = line + a;
168 i++;
169 n++;
170
171 /* Compressed */
172 for(; n < linesize && line[n] == ' '; n++);
173 a = n;
174 for(; n < linesize && line[n] != ' '; n++);
175 line[n]='\0';
176 item[i] = line + a;
177 i++;
178 n++;
179
180 /* Ratio */
181 for(; n < linesize && line[n] == ' '; n++);
182 a = n;
183 for(; n < linesize && line[n] != ' '; n++);
184 line[n] = '\0';
185 item[i] = line + a;
186 i++;
187 n++;
188
189 /* Date */
190 for(; n < linesize && line[n] == ' '; n++);
191 a = n;
192 for(; n < linesize && line[n] != ' '; n++);
193 line[n] = '\0';
194 item[i] = date_DD_MM_YY(line + a);
195 i++;
196 n++;
197
198 /* Time */
199 for(; n < linesize && line[n] == ' '; n++);
200 a = n;
201 for(; n < linesize && line[n] != ' '; n++);
202 line[n] = '\0';
203 item[i] = line + a;
204 i++;
205 n++;
206
207 /* Permissions */
208 for(; n < linesize && line[n] == ' '; n++);
209 a = n;
210 for(; n < linesize && line[n] != ' '; n++);
211 line[n] = '\0';
212 /* archive may originate from Unix or Windows type OS */
213 if (*(line + a) == 'd' || *(line + a + 1) == 'D')
214 dir = TRUE;
215 item[i] = line + a;
216 i++;
217 n++;
218
219 /* CRC */
220 for(; n < linesize && line[n] == ' '; n++);
221 a = n;
222 for(; n < linesize && line[n] != ' '; n++);
223 line[n] = '\0';
224 item[i] = line + a;
225 i++;
226 n++;
227
228 /* Method */
229 for(; n < linesize && line[n] == ' '; n++);
230 a = n;
231 for(; n < linesize && line[n] != ' '; n++);
232 line[n] = '\0';
233 item[i] = line + a;
234 i++;
235 n++;
236
237 /* version */
238 for(; n < linesize && line[n] == ' '; n++);
239 a = n;
240 for(; n < linesize && line[n] != ' ' && line[n] != '\n'; n++);
241 line[n] = '\0';
242 item[i] = line + a;
243
244 entry = xa_set_archive_entries_for_each_row(archive, filename, item);
245
246 if (entry)
247 {
248 if (dir)
249 entry->is_dir = TRUE;
250
251 entry->is_encrypted = encrypted;
252
253 if (!entry->is_dir)
254 archive->files++;
255
256 archive->files_size += g_ascii_strtoull(item[0], NULL, 0);
257 }
258
259 g_free(filename);
260 fname_line = FALSE;
261 }
262 }
263
xa_rar5_parse_output(gchar * line,XArchive * archive)264 static void xa_rar5_parse_output (gchar *line, XArchive *archive)
265 {
266 XEntry *entry;
267 gpointer item[7];
268 unsigned short int i = 0;
269 unsigned int linesize, n, a;
270 gboolean encrypted = FALSE, dir = FALSE;
271 static gchar *filename, *end;
272
273 if (last_line)
274 return;
275
276 if (!data_line)
277 {
278 if (!header_line)
279 {
280 if ((strncmp(line, "Archive: ", 9) == 0) && strstr(line, archive->path[0]))
281 {
282 header_line = TRUE;
283
284 if (archive->comment)
285 {
286 if (archive->comment->len > 2)
287 {
288 archive->has_comment = TRUE;
289 archive->comment = g_string_truncate(archive->comment, archive->comment->len - 2);
290 archive->comment = g_string_erase(archive->comment, 0, 1);
291 }
292 else
293 {
294 g_string_free(archive->comment, TRUE);
295 archive->comment = NULL;
296 }
297 }
298 }
299 else
300 {
301 if (!archive->comment)
302 archive->comment = g_string_new("");
303
304 archive->comment = g_string_append(archive->comment, line);
305 }
306 return;
307 }
308 if (line[0] == '-')
309 {
310 data_line = TRUE;
311 return;
312 }
313 return;
314 }
315
316 linesize = strlen(line);
317 line[linesize - 1] = '\0';
318
319 if(line[0] == '*')
320 {
321 archive->has_password = TRUE;
322 encrypted = TRUE;
323 }
324 else if (line[0] == '-')
325 {
326 last_line = TRUE;
327 return;
328 }
329
330 /* Permissions */
331 for (n = encrypted ? 1 : 0; n < linesize && line[n] == ' '; n++);
332 a = n;
333 for(; n < linesize && line[n] != ' '; n++);
334 line[n] = '\0';
335 /* archive may originate from Unix or Windows type OS */
336 if (*(line + a) == 'd' || *(line + a + 3) == 'D')
337 dir = TRUE;
338 item[5] = line + a;
339 n++;
340
341 /* Size */
342 for(; n < linesize && line[n] == ' '; n++);
343 a = n;
344 for(; n < linesize && line[n] != ' '; n++);
345 line[n]='\0';
346 item[i] = line + a;
347 i++;
348 n++;
349
350 /* Compressed */
351 for(; n < linesize && line[n] == ' '; n++);
352 a = n;
353 for(; n < linesize && line[n] != ' '; n++);
354 line[n]='\0';
355 item[i] = line + a;
356 i++;
357 n++;
358
359 /* Ratio */
360 for(; n < linesize && line[n] == ' '; n++);
361 a = n;
362 for(; n < linesize && line[n] != ' '; n++);
363 line[n] = '\0';
364 item[i] = line + a;
365 i++;
366 n++;
367
368 /* Date */
369 for(; n < linesize && line[n] == ' '; n++);
370 a = n;
371 for(; n < linesize && line[n] != ' '; n++);
372 line[n] = '\0';
373 item[i] = line + a; // date is YYYY-MM-DD since v5.30
374 if (strlen(item[i]) != 10) // and was DD-MM-YY before
375 item[i] = date_DD_MM_YY(item[i]);
376 i++;
377 n++;
378
379 /* Time */
380 for(; n < linesize && line[n] == ' '; n++);
381 a = n;
382 for(; n < linesize && line[n] != ' '; n++);
383 line[n] = '\0';
384 item[i] = line + a;
385 i+=2;
386 n++;
387
388 /* CRC */
389 for(; n < linesize && line[n] == ' '; n++);
390 a = n;
391 for(; n < linesize && line[n] != ' '; n++);
392 line[n] = '\0';
393 item[i] = line + a;
394
395 /* FileName */
396 line[linesize - 1] = '\0';
397 filename = g_strdup(line + n + 2);
398
399 /* Strip trailing whitespace */
400 end = filename + strlen(filename) - 1;
401 while(end >= filename && *end == ' ') end--;
402 *(end + 1) = '\0';
403
404 entry = xa_set_archive_entries_for_each_row (archive,filename,item);
405
406 if (entry)
407 {
408 if (dir)
409 entry->is_dir = TRUE;
410
411 entry->is_encrypted = encrypted;
412
413 if (!entry->is_dir)
414 archive->files++;
415
416 archive->files_size += g_ascii_strtoull(item[0], NULL, 0);
417 }
418
419 g_free(filename);
420 }
421
xa_rar_list(XArchive * archive)422 void xa_rar_list (XArchive *archive)
423 {
424 GIOChannel *file;
425 gchar *password_str, *command;
426 guint i;
427
428 file = g_io_channel_new_file(archive->path[0], "r", NULL);
429
430 if (file)
431 {
432 gchar byte[2];
433
434 g_io_channel_set_encoding(file, NULL, NULL);
435
436 /* skip RAR 4 and 5 common signature part */
437 g_io_channel_seek_position(file, 6, G_SEEK_SET, NULL);
438
439 g_io_channel_read_chars(file, byte, sizeof(*byte), NULL, NULL);
440
441 /* RAR 4 archive */
442 if (*byte == 0)
443 {
444 /* skip header CRC16 */
445 g_io_channel_seek_position(file, 2, G_SEEK_CUR, NULL);
446
447 /* block type */
448 g_io_channel_read_chars(file, &byte[0], sizeof(*byte), NULL, NULL);
449
450 /* block flag */
451 g_io_channel_read_chars(file, &byte[1], sizeof(*byte), NULL, NULL);
452
453 archive->has_password = (byte[0] == 0x73 && byte[1] & 0x80);
454 }
455 /* RAR 5 archive */
456 else
457 {
458 /* skip last signature byte and header CRC32 */
459 g_io_channel_seek_position(file, 5, G_SEEK_CUR, NULL);
460
461 /* skip vint header size */
462 do
463 g_io_channel_read_chars(file, byte, sizeof(*byte), NULL, NULL);
464 while (*byte & 0x80);
465
466 /* header type */
467 g_io_channel_read_chars(file, byte, sizeof(*byte), NULL, NULL);
468
469 archive->has_password = (*byte == 4);
470 }
471
472 g_io_channel_shutdown(file, FALSE, NULL);
473
474 if (archive->has_password)
475 if (!xa_check_password(archive))
476 return;
477 }
478
479 header_line = FALSE;
480 data_line = FALSE;
481 fname_line = FALSE;
482 last_line = FALSE;
483
484 password_str = xa_rar_password_str(archive);
485 command = g_strconcat(archiver[archive->type].program[0], " v", password_str, " -idc ", archive->path[1], NULL);
486 g_free(password_str);
487
488 archive->files_size = 0;
489 archive->files = 0;
490
491
492 if (rar_version >= 5)
493 {
494 const GType types[] = {GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER};
495 const gchar *titles[] = {_("Original Size"), _("Compressed"), _("Occupancy"), _("Date"), _("Time"), _("Attributes"), _("Checksum")};
496
497 archive->parse_output = xa_rar5_parse_output;
498 xa_spawn_async_process (archive,command);
499 g_free ( command );
500
501 archive->columns = 10;
502 archive->size_column = 2;
503 archive->column_types = g_malloc0(sizeof(types));
504
505 for (i = 0; i < archive->columns; i++)
506 archive->column_types[i] = types[i];
507
508 xa_create_liststore(archive, titles);
509 }
510 else
511 {
512 const GType types[] = {GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER};
513 const gchar *titles[] = {_("Original Size"), _("Compressed"), _("Occupancy"), _("Date"), _("Time"), _("Attributes"), _("Checksum"), _("Method"), _("Version")};
514
515 archive->parse_output = xa_rar_parse_output;
516 xa_spawn_async_process (archive,command);
517 g_free ( command );
518
519 archive->columns = 12;
520 archive->size_column = 2;
521 archive->column_types = g_malloc0(sizeof(types));
522
523 for (i = 0; i < archive->columns; i++)
524 archive->column_types[i] = types[i];
525
526 xa_create_liststore(archive, titles);
527 }
528 }
529
xa_rar_test(XArchive * archive)530 void xa_rar_test (XArchive *archive)
531 {
532 gchar *password_str, *command;
533
534 password_str = xa_rar_password_str(archive);
535 command = g_strconcat(archiver[archive->type].program[0], " t", password_str, " -idp -y ", archive->path[1], NULL);
536 g_free(password_str);
537
538 xa_run_command(archive, command);
539 g_free(command);
540 }
541
542 /*
543 * Note: rar does not seem to be able to handle wildcards in file names.
544 */
545
xa_rar_extract(XArchive * archive,GSList * file_list)546 gboolean xa_rar_extract (XArchive *archive, GSList *file_list)
547 {
548 GString *files;
549 gchar *password_str, *command;
550 gboolean result;
551
552 files = xa_quote_filenames(file_list, NULL, FALSE);
553 password_str = xa_rar_password_str(archive);
554 command = g_strconcat(archiver[archive->type].program[0],
555 archive->do_full_path ? " x" : " e",
556 archive->do_touch ? " -tsm-" : "",
557 archive->do_overwrite ? " -o+" : (archive->do_update ? " -u" : (archive->do_freshen ? " -f" : " -o-")),
558 password_str, " -idp -y ",
559 archive->path[1], files->str,
560 " ", archive->extraction_dir, NULL);
561 g_free(password_str);
562 g_string_free(files,TRUE);
563
564 result = xa_run_command(archive, command);
565 g_free(command);
566
567 return result;
568 }
569
xa_rar_add(XArchive * archive,GSList * file_list,gchar * compression)570 void xa_rar_add (XArchive *archive, GSList *file_list, gchar *compression)
571 {
572 GString *files;
573 gchar *password_str, *command, *version_switch;
574
575
576 if (archive->location_path != NULL)
577 archive->child_dir = g_strdup(archive->working_dir);
578
579 if (rar_version >= 5)
580 {
581 if (archive->tag == 5)
582 version_switch = " -ma5";
583 else
584 version_switch = " -ma4";
585 }
586 else
587 version_switch = "";
588
589 if (!compression)
590 compression = "3";
591
592 files = xa_quote_filenames(file_list, NULL, FALSE);
593 password_str = xa_rar_password_str(archive);
594 command = g_strconcat(archiver[archive->type].program[0],
595 archive->do_update ? " u" : " a", version_switch,
596 archive->do_freshen ? " -f" : "",
597 archive->do_move ? " -df" : "",
598 archive->do_solid ? " -s" : "",
599 " -m", compression,
600 password_str, " -idp -y ",
601 archive->path[1], files->str, NULL);
602 g_free(password_str);
603 g_string_free(files,TRUE);
604
605 xa_run_command(archive, command);
606 g_free(command);
607 }
608
xa_rar_delete(XArchive * archive,GSList * file_list)609 void xa_rar_delete (XArchive *archive, GSList *file_list)
610 {
611 GString *files;
612 gchar *command;
613
614 files = xa_quote_filenames(file_list, NULL, FALSE);
615 command = g_strconcat(archiver[archive->type].program[0], " d -idp -y ", archive->path[1], files->str, NULL);
616 g_string_free(files,TRUE);
617
618 xa_run_command(archive, command);
619 g_free(command);
620 }
621