1 /*
2  *  Copyright (C) 2017 Ingo Brückl
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 "cpio.h"
22 #include "date_utils.h"
23 #include "main.h"
24 #include "parser.h"
25 #include "string_utils.h"
26 #include "support.h"
27 #include "window.h"
28 
relative_path(char * filename,gpointer user_data)29 static void relative_path (char *filename, gpointer user_data)
30 {
31 	if (*filename == '/')
32 		strcpy(filename, filename + 1);
33 }
34 
xa_cpio_ask(XArchive * archive)35 void xa_cpio_ask (XArchive *archive)
36 {
37 	archive->can_extract = TRUE;
38 	archive->can_add = TRUE;
39 	archive->can_full_path[0] = TRUE;
40 	archive->can_full_path[1] = TRUE;   // n.b.: adds leading slash
41 	archive->can_touch = TRUE;
42 	archive->can_overwrite = TRUE;
43 }
44 
xa_cpio_parse_output(gchar * line,XArchive * archive)45 static void xa_cpio_parse_output (gchar *line, XArchive *archive)
46 {
47 	XEntry *entry;
48 	gpointer item[7];
49 	gchar *filename, time[6];
50 	gboolean dev, dir, link;
51 
52 	USE_PARSER;
53 
54 	/* permissions */
55 	NEXT_ITEM(item[4]);
56 
57 	dev = (*(char *) item[4] == 'b' || *(char *) item[4] == 'c');
58 	dir = (*(char *) item[4] == 'd');
59 	link = (*(char *) item[4] == 'l');
60 
61 	/* number of links */
62 	SKIP_ITEM;
63 
64 	/* owner */
65 	NEXT_ITEM(item[5]);
66 
67 	/* group */
68 	NEXT_ITEM(item[6]);
69 
70 	/* size */
71 	if (dev)
72 	{
73 		SKIP_ITEM;
74 		SKIP_ITEM;
75 		item[1] = "0";
76 	}
77 	else
78 		NEXT_ITEM(item[1]);
79 
80 	/* date and time */
81 	NEXT_ITEMS(3, item[2]);
82 
83 	/* time */
84 	if (((char *) item[2])[9] == ':')
85 	{
86 		memcpy(time, item[2] + 7, 5);
87 		time[5] = 0;
88 	}
89 	else
90 		strcpy(time, "-----");
91 
92 	item[2] = date_MMM_dD_HourYear(item[2]);
93 	item[3] = time;
94 
95 	/* name */
96 	LAST_ITEM(filename);
97 
98 	item[0] = NULL;
99 
100 	if (link)
101 	{
102 		char *l = strstr(filename, " -> ");
103 
104 		if (l)
105 		{
106 			item[0] = l + 4;
107 			*l = 0;
108 		}
109 	}
110 
111 	entry = xa_set_archive_entries_for_each_row(archive, filename, item);
112 
113 	if (entry)
114 	{
115 		if (dir)
116 			entry->is_dir = TRUE;
117 
118 		if (!entry->is_dir)
119 			archive->files++;
120 
121 		archive->files_size += g_ascii_strtoull(item[1], NULL, 0);
122 	}
123 }
124 
xa_cpio_list(XArchive * archive)125 void xa_cpio_list (XArchive *archive)
126 {
127 	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_STRING, G_TYPE_POINTER};
128 	const gchar *titles[] = {_("Points to"), _("Original Size"), _("Date"), _("Time"), _("Permissions"), _("Owner"), _("Group")};
129 	gchar *command;
130 	guint i;
131 
132 	archive->files = 0;
133 	archive->files_size = 0;
134 
135 	command = g_strconcat(archiver[archive->type].program[0], " -tv -F ", archive->path[1], NULL);
136 	archive->parse_output = xa_cpio_parse_output;
137 	xa_spawn_async_process(archive, command);
138 	g_free(command);
139 
140 	archive->columns = 10;
141 	archive->size_column = 3;
142 	archive->column_types = g_malloc0(sizeof(types));
143 
144 	for (i = 0; i < archive->columns; i++)
145 		archive->column_types[i] = types[i];
146 
147 	xa_create_liststore(archive, titles);
148 }
149 
150 /*
151  * Note: cpio lists ' ' as '\ ', '"' as '\"' and '\' as '\\' while it
152  * extracts ' ', '"' and '\' respectively, i.e. file names containing
153  * one of these three characters can't be handled entirely.
154  */
155 
xa_cpio_extract(XArchive * archive,GSList * file_list)156 gboolean xa_cpio_extract (XArchive *archive, GSList *file_list)
157 {
158 	GString *files;
159 	gchar *extract_to, *command;
160 	gboolean result;
161 
162 	if (archive->do_full_path)
163 		extract_to = g_strdup(archive->extraction_dir);
164 	else
165 	{
166 		if (!xa_create_working_directory(archive))
167 			return FALSE;
168 
169 		extract_to = g_strconcat(archive->working_dir, "/xa-tmp.XXXXXX", NULL);
170 
171 		if (!g_mkdtemp(extract_to))
172 		{
173 			g_free(extract_to);
174 			return FALSE;
175 		}
176 	}
177 
178 	g_slist_foreach(file_list, (GFunc) relative_path, NULL);
179 	files = xa_quote_filenames(file_list, "*?[]\"", FALSE);
180 	archive->child_dir = g_strdup(extract_to);
181 	command = g_strconcat(archiver[archive->type].program[0], " -id",
182 	                      archive->do_touch ? "" : " -m",
183 	                      archive->do_overwrite ? " -u" : "",
184 	                      " --no-absolute-filenames -F ", archive->path[1],
185 	                      files->str, NULL);
186 	result = xa_run_command(archive, command);
187 	g_free(command);
188 
189 	g_free(archive->child_dir);
190 	archive->child_dir = NULL;
191 
192 	/* collect all files that have been extracted to move them without full path */
193 	if (result && !archive->do_full_path)
194 	{
195 		GString *all_files = xa_collect_files_in_dir(extract_to);
196 
197 		archive->child_dir = g_strdup(extract_to);
198 		command = g_strconcat("mv",
199 		                      archive->do_overwrite ? " -f" : " -n",
200 		                      all_files->str, " ", archive->extraction_dir, NULL);
201 		g_string_free(all_files, TRUE);
202 
203 		result = xa_run_command(archive, command);
204 		g_free(command);
205 
206 		g_free(archive->child_dir);
207 		archive->child_dir = NULL;
208 	}
209 
210 	g_free(extract_to);
211 	g_string_free(files, TRUE);
212 
213 	return result;
214 }
215 
xa_cpio_add(XArchive * archive,GSList * file_list,gchar * compression)216 void xa_cpio_add (XArchive *archive, GSList *file_list, gchar *compression)
217 {
218 	GString *files;
219 	gchar *archive_path, *command;
220 
221 	if (archive->location_path != NULL)
222 		archive->child_dir = g_strdup(archive->working_dir);
223 
224 	// no option for compression
225 
226 	files = xa_quote_filenames(file_list, "\"", FALSE);
227 	archive_path = xa_quote_shell_command(archive->path[0], TRUE);
228 	command = g_strconcat("sh -c \"", "ls -d", files->str, " | ",
229 	                      archiver[archive->type].program[0], " -o",
230 	                      g_file_test(archive->path[0], G_FILE_TEST_EXISTS) ? " -A" : "",
231 	                      " -F ", archive_path, "\"", NULL);
232 	g_free(archive_path);
233 	g_string_free(files, TRUE);
234 
235 	xa_run_command(archive, command);
236 	g_free(command);
237 }
238