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 "tar.h"
22 #include "gzip_et_al.h"
23 #include "main.h"
24 #include "string_utils.h"
25 #include "support.h"
26 #include "window.h"
27
isTar(FILE * file)28 gboolean isTar (FILE *file)
29 {
30 unsigned char magic[8];
31 gboolean result;
32
33 fseek(file, 0, SEEK_SET);
34
35 if (fseek(file, 257, SEEK_CUR) != 0 ||
36 fread(magic, sizeof(magic), 1, file) != 1)
37 {
38 fseek(file, 0, SEEK_SET);
39 return FALSE;
40 }
41
42 result = (memcmp(magic, "ustar" "\x00" "00", sizeof(magic)) == 0 ||
43 memcmp(magic, "ustar" " " "\x00", sizeof(magic)) == 0);
44
45 if (!result &&
46 memcmp(magic, "\x00\x00\x00\x00\x00\x00\x00\x00", sizeof(magic)) == 0)
47 {
48 /* next block */
49 if (fseek(file, 512, SEEK_SET) == 0 &&
50 fread(magic, sizeof(*magic), 1, file) == 1)
51 result = (*magic != 0);
52 }
53
54 fseek(file, 0, SEEK_SET);
55
56 return result;
57 }
58
xa_tar_get_compressor_type(XArchive * archive)59 static XArchiveType xa_tar_get_compressor_type (XArchive *archive)
60 {
61 switch (archive->type)
62 {
63 case XARCHIVETYPE_TAR_BZIP2:
64 return XARCHIVETYPE_BZIP2;
65
66 case XARCHIVETYPE_TAR_COMPRESS:
67 return XARCHIVETYPE_COMPRESS;
68
69 case XARCHIVETYPE_TAR_GZIP:
70 return XARCHIVETYPE_GZIP;
71
72 case XARCHIVETYPE_TAR_LRZIP:
73 return XARCHIVETYPE_LRZIP;
74
75 case XARCHIVETYPE_TAR_LZ4:
76 return XARCHIVETYPE_LZ4;
77
78 case XARCHIVETYPE_TAR_LZIP:
79 return XARCHIVETYPE_LZIP;
80
81 case XARCHIVETYPE_TAR_LZMA:
82 return XARCHIVETYPE_LZMA;
83
84 case XARCHIVETYPE_TAR_LZOP:
85 return XARCHIVETYPE_LZOP;
86
87 case XARCHIVETYPE_TAR_XZ:
88 return XARCHIVETYPE_XZ;
89
90 case XARCHIVETYPE_TAR_ZSTD:
91 return XARCHIVETYPE_ZSTD;
92
93 default:
94 return XARCHIVETYPE_TAR;
95 }
96 }
97
xa_tar_ask(XArchive * archive)98 void xa_tar_ask (XArchive *archive)
99 {
100 archive->can_extract = TRUE;
101 archive->can_add = archiver[xa_tar_get_compressor_type(archive)].is_compressor;
102 archive->can_delete = archiver[xa_tar_get_compressor_type(archive)].is_compressor;
103 archive->can_full_path[0] = TRUE;
104 archive->can_full_path[1] = archiver[xa_tar_get_compressor_type(archive)].is_compressor;
105 archive->can_touch = TRUE;
106 archive->can_overwrite = TRUE;
107 archive->can_update[0] = TRUE;
108 archive->can_update[1] = archiver[xa_tar_get_compressor_type(archive)].is_compressor;
109 archive->can_move = archiver[xa_tar_get_compressor_type(archive)].is_compressor;
110
111 /* this is solely for display with the archive properties */
112 if (!archiver[archive->type].program[0])
113 {
114 archiver[archive->type].program[0] = g_strdup(archiver[xa_tar_get_compressor_type(archive)].program[0]);
115 archiver[archive->type].program[1] = g_strdup(archiver[XARCHIVETYPE_TAR].program[0]);
116 }
117 }
118
xa_tar_parse_output(gchar * line,XArchive * archive)119 static void xa_tar_parse_output (gchar *line, XArchive *archive)
120 {
121 XEntry *entry;
122 gchar *filename;
123 gpointer item[6];
124 gint n = 0, a = 0 ,linesize = 0;
125
126 linesize = strlen(line);
127
128 /* Permissions */
129 line[10] = '\0';
130 item[4] = line;
131
132 /* Owner */
133 for(n=13; n < linesize; ++n)
134 if(line[n] == ' ')
135 break;
136 line[n] = '\0';
137 item[5] = line+11;
138
139 /* Size */
140 for(++n; n < linesize; ++n)
141 if(line[n] >= '0' && line[n] <= '9')
142 break;
143 a = n;
144
145 for(; n < linesize; ++n)
146 if(line[n] == ' ')
147 break;
148
149 line[n] = '\0';
150 item[1] = line + a;
151 a = ++n;
152
153 /* Date */
154 for(; n < linesize; n++)
155 if(line[n] == ' ')
156 break;
157
158 line[n] = '\0';
159 item[2] = line + a;
160
161 /* Time */
162 a = ++n;
163 for (; n < linesize; n++)
164 if (line[n] == ' ')
165 break;
166
167 line[n] = '\0';
168 item[3] = line + a;
169 n++;
170 line[linesize-1] = '\0';
171
172 filename = line + n;
173
174 /* Symbolic link */
175 gchar *temp = g_strrstr (filename,"->");
176 if (temp)
177 {
178 gint len = strlen(filename) - strlen(temp);
179 item[0] = (filename +=3) + len;
180 filename[strlen(filename) - strlen(temp)-1] = '\0';
181 }
182 else
183 item[0] = NULL;
184
185 if(line[0] == 'd')
186 {
187 /* Work around for gtar, which does not output / with directories */
188 if(line[linesize-2] != '/')
189 filename = g_strconcat(line + n, "/", NULL);
190 else
191 filename = g_strdup(line + n);
192 }
193 else
194 filename = g_strdup(line + n);
195
196 entry = xa_set_archive_entries_for_each_row(archive, filename, item);
197
198 if (entry)
199 {
200 entry->is_encrypted = (archive->password != NULL);
201
202 if (!entry->is_dir)
203 archive->files++;
204
205 archive->files_size += g_ascii_strtoull(item[1], NULL, 0);
206 }
207
208 g_free(filename);
209 }
210
xa_tar_list(XArchive * archive)211 void xa_tar_list (XArchive *archive)
212 {
213 const GType types[] = {GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER};
214 const gchar *titles[] = {_("Points to"), _("Original Size"), _("Date"), _("Time"), _("Permissions"), _("Owner/Group")};
215 gchar *command;
216 guint i;
217
218 if (!archive->path[2])
219 archive->path[2] = g_shell_quote(archive->path[0]);
220
221 archive->files = 0;
222 archive->files_size = 0;
223
224 command = g_strconcat(archiver[XARCHIVETYPE_TAR].program[0], " -tvf ", archive->path[2], NULL);
225 archive->parse_output = xa_tar_parse_output;
226 xa_spawn_async_process(archive, command);
227 g_free(command);
228
229 archive->columns = 9;
230 archive->size_column = 3;
231 archive->column_types = g_malloc0(sizeof(types));
232
233 for (i = 0; i < archive->columns; i++)
234 archive->column_types[i] = types[i];
235
236 xa_create_liststore(archive, titles);
237 }
238
239 /*
240 * Note: tar lists '\' as '\\' while it extracts '\', i.e.
241 * file names containing this character can't be handled entirely.
242 */
243
xa_tar_extract(XArchive * archive,GSList * file_list)244 gboolean xa_tar_extract (XArchive *archive, GSList *file_list)
245 {
246 GString *files;
247 gchar *extract_to, *command;
248 gboolean result;
249
250 if (archive->do_full_path)
251 extract_to = g_strdup(archive->extraction_dir);
252 else
253 {
254 if (!xa_create_working_directory(archive))
255 return FALSE;
256
257 extract_to = g_strconcat(archive->working_dir, "/xa-tmp.XXXXXX", NULL);
258
259 if (!g_mkdtemp(extract_to))
260 {
261 g_free(extract_to);
262 return FALSE;
263 }
264 }
265
266 files = xa_quote_filenames(file_list, NULL, TRUE);
267 command = g_strconcat(archiver[XARCHIVETYPE_TAR].program[0],
268 " -x --no-recursion --no-wildcards",
269 " -f ", archive->path[2],
270 archive->do_touch ? " -m" : "",
271 archive->do_overwrite ? "" : (archive->do_update ? " --keep-newer-files" : " -k"),
272 " -C ", extract_to, files->str, NULL);
273
274 result = xa_run_command(archive, command);
275 g_free(command);
276
277 /* collect all files that have been extracted to move them without full path */
278 if (result && !archive->do_full_path)
279 {
280 GString *all_files = xa_collect_files_in_dir(extract_to);
281
282 archive->child_dir = g_strdup(extract_to);
283 command = g_strconcat("mv",
284 archive->do_overwrite ? " -f" : " -n",
285 archive->do_update ? " -fu" : "",
286 all_files->str, " ", archive->extraction_dir, NULL);
287 g_string_free(all_files, TRUE);
288
289 result = xa_run_command(archive, command);
290 g_free(command);
291
292 g_free(archive->child_dir);
293 archive->child_dir = NULL;
294 }
295
296 g_free(extract_to);
297 g_string_free(files, TRUE);
298
299 return result;
300 }
301
xa_tar_add(XArchive * archive,GSList * file_list,gchar * compression)302 void xa_tar_add (XArchive *archive, GSList *file_list, gchar *compression)
303 {
304 GString *files;
305 gchar *command;
306
307 if (archive->location_path != NULL)
308 archive->child_dir = g_strdup(archive->working_dir);
309
310 files = xa_quote_filenames(file_list, NULL, TRUE);
311
312 if (!g_file_test(archive->path[0], G_FILE_TEST_EXISTS))
313 {
314 if (archive->type == XARCHIVETYPE_TAR)
315 archive->path[2] = g_shell_quote(archive->path[0]);
316 else
317 {
318 gchar *workfile;
319
320 if (!xa_create_working_directory(archive))
321 {
322 g_string_free(files, TRUE);
323 return;
324 }
325
326 workfile = g_strconcat(archive->working_dir, "/xa-tmp.tar", NULL);
327 archive->path[2] = g_shell_quote(workfile);
328 g_free(workfile);
329 }
330
331 command = g_strconcat(archiver[XARCHIVETYPE_TAR].program[0],
332 " -c --no-recursion --no-wildcards",
333 archive->do_move ? " --remove-files" : "",
334 " -f ", archive->path[2], files->str, NULL);
335 }
336 else
337 command = g_strconcat(archiver[XARCHIVETYPE_TAR].program[0],
338 archive->do_update ? " -u" : " -r",
339 " --no-recursion --no-wildcards",
340 archive->do_move ? " --remove-files" : "",
341 " -f ", archive->path[2], files->str, NULL);
342
343 if (archive->type != XARCHIVETYPE_TAR)
344 {
345 xa_run_command(archive, command);
346 g_free(command);
347
348 command = xa_gzip_et_al_get_command(archiver[xa_tar_get_compressor_type(archive)].program[0], archive->path[2], archive->path[0], archive->password, xa_tar_get_compressor_type(archive));
349 }
350
351 g_string_free(files, TRUE);
352
353 xa_run_command(archive, command);
354 g_free(command);
355 }
356
xa_tar_delete(XArchive * archive,GSList * file_list)357 void xa_tar_delete (XArchive *archive, GSList *file_list)
358 {
359 GString *files;
360 gchar *command;
361
362 files = xa_quote_filenames(file_list, NULL, TRUE);
363 command = g_strconcat(archiver[XARCHIVETYPE_TAR].program[0], " --delete --no-recursion --no-wildcards -f ", archive->path[2], files->str, NULL);
364
365 if (archive->type != XARCHIVETYPE_TAR)
366 {
367 xa_run_command(archive, command);
368 g_free(command);
369
370 command = xa_gzip_et_al_get_command(archiver[xa_tar_get_compressor_type(archive)].program[0], archive->path[2], archive->path[0], archive->password, xa_tar_get_compressor_type(archive));
371 }
372
373 g_string_free(files, TRUE);
374
375 xa_run_command(archive, command);
376 g_free(command);
377 }
378