/[gentoo-projects]/portage-utils/qtbz2.c
Gentoo

Contents of /portage-utils/qtbz2.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.21 - (show annotations) (download) (as text)
Sat Nov 17 18:44:58 2012 UTC (2 years, 1 month ago) by vapier
Branch: MAIN
Changes since 1.20: +7 -2 lines
File MIME type: text/x-csrc
qtbz2: add magic checks to catch accidental argument swapping

1 /*
2 * Copyright 2005-2010 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/portage-utils/qtbz2.c,v 1.20 2012/11/17 18:25:22 vapier Exp $
5 *
6 * Copyright 2005-2010 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2005-2010 Mike Frysinger - <vapier@gentoo.org>
8 */
9
10 #ifdef APPLET_qtbz2
11
12 /*
13 # The format for a tbz2/xpak:
14 #
15 # tbz2: tar.bz2 + xpak + (xpak_offset) + "STOP"
16 # xpak: "XPAKPACK" + (index_len) + (data_len) + index + data + "XPAKSTOP"
17 # index: (pathname_len) + pathname + (data_offset) + (data_len)
18 # index entries are concatenated end-to-end.
19 # data: concatenated data chunks, end-to-end.
20 #
21 # [tarball]XPAKPACKIIIIDDDD[index][data]XPAKSTOPOOOOSTOP
22 #
23 # (integer) == encodeint(integer) ===> 4 characters (big-endian copy)
24 # '+' means concatenate the fields ===> All chunks are strings
25 */
26 #define TBZ2_END_MSG "STOP"
27 #define TBZ2_END_MSG_LEN 4
28 #define TBZ2_END_LEN (4 + TBZ2_END_MSG_LEN)
29
30 #define QTBZ2_FLAGS "d:jstxO" COMMON_FLAGS
31 static struct option const qtbz2_long_opts[] = {
32 {"dir", a_argument, NULL, 'd'},
33 {"join", no_argument, NULL, 'j'},
34 {"split", no_argument, NULL, 's'},
35 {"tarbz2", no_argument, NULL, 't'},
36 {"xpak", no_argument, NULL, 'x'},
37 {"stdout", no_argument, NULL, 'O'},
38 COMMON_LONG_OPTS
39 };
40 static const char * const qtbz2_opts_help[] = {
41 "Change to specified directory",
42 "Join: <tar.bz2> <xpak> <tbz2>",
43 "Split a tbz2 into a tar.bz2 + xpak",
44 "Just split the tar.bz2",
45 "Just split the xpak",
46 "Write files to stdout",
47 COMMON_OPTS_HELP
48 };
49 static const char qtbz2_rcsid[] = "$Id: qtbz2.c,v 1.20 2012/11/17 18:25:22 vapier Exp $";
50 #define qtbz2_usage(ret) usage(ret, QTBZ2_FLAGS, qtbz2_long_opts, qtbz2_opts_help, lookup_applet_idx("qtbz2"))
51
52 static char tbz2_stdout = 0;
53
54 unsigned char *tbz2_encode_int(int enc);
55 unsigned char *tbz2_encode_int(int enc)
56 {
57 static unsigned char ret[4];
58 ret[0] = (enc & 0xff000000) >> 24;
59 ret[1] = (enc & 0x00ff0000) >> 16;
60 ret[2] = (enc & 0x0000ff00) >> 8;
61 ret[3] = (enc & 0x000000ff);
62 return ret;
63 }
64 int tbz2_decode_int(unsigned char *buf);
65 int tbz2_decode_int(unsigned char *buf)
66 {
67 int ret;
68 ret = 0;
69 ret += (buf[0] << 24);
70 ret += (buf[1] << 16);
71 ret += (buf[2] << 8);
72 ret += (buf[3]);
73 return ret;
74 }
75
76 void _tbz2_copy_file(FILE *src, FILE *dst);
77 void _tbz2_copy_file(FILE *src, FILE *dst)
78 {
79 int count = 1;
80 unsigned char buffer[BUFSIZE*32];
81 while (count) {
82 count = fread(buffer, 1, sizeof(buffer), src);
83 if (!count) return;
84 fwrite(buffer, 1, count, dst);
85 }
86 }
87
88 static int
89 tbz2_compose(int dir_fd, const char *tarbz2, const char *xpak, const char *tbz2)
90 {
91 FILE *out, *in_tarbz2, *in_xpak;
92 struct stat st;
93 int ret = 1, fd;
94 char buf[8];
95
96 if (verbose)
97 printf("input xpak: %s\ninput tar.bz2: %s\noutput tbz2: %s\n",
98 xpak, tarbz2, tbz2);
99
100 /* open tbz2 output */
101 if ((out = fopen(tbz2, "w")) == NULL)
102 return ret;
103 /* open tar.bz2 input */
104 fd = openat(dir_fd, tarbz2, O_RDONLY|O_CLOEXEC);
105 if (fd < 0) {
106 fclose(out);
107 return ret;
108 }
109 if (pread(fd, buf, 3, 0) != 3 || memcmp(buf, "BZh", 3))
110 warn("%s: does not appear to be a .tar.bz2", tarbz2);
111 in_tarbz2 = fdopen(fd, "r");
112 if (in_tarbz2 == NULL) {
113 fclose(out);
114 close(fd);
115 return ret;
116 }
117 /* open xpak input */
118 fd = openat(dir_fd, xpak, O_RDONLY|O_CLOEXEC);
119 if (fd < 0) {
120 fclose(out);
121 fclose(in_tarbz2);
122 return ret;
123 }
124 if (pread(fd, buf, 8, 0) != 8 || memcmp(buf, "XPAKPACK", 8))
125 warn("%s: does not appear to be a .xpak", xpak);
126 in_xpak = fdopen(fd, "r");
127 if (in_xpak == NULL) {
128 fclose(out);
129 fclose(in_tarbz2);
130 close(fd);
131 return ret;
132 }
133 if (fstat(fd, &st)) {
134 fclose(out);
135 fclose(in_tarbz2);
136 fclose(in_xpak);
137 return ret;
138 }
139
140 /* save [tarball] */
141 _tbz2_copy_file(in_tarbz2, out);
142 fclose(in_tarbz2);
143 /* save [xpak] */
144 _tbz2_copy_file(in_xpak, out);
145 fclose(in_xpak);
146
147 /* save tbz2 tail: OOOOSTOP */
148 fwrite(tbz2_encode_int(st.st_size), 1, 4, out);
149 fwrite(TBZ2_END_MSG, 1, TBZ2_END_MSG_LEN, out);
150
151 fclose(out);
152 ret = 0;
153 return ret;
154 }
155
156 static void
157 _tbz2_write_file(FILE *src, int dir_fd, const char *dst, size_t len)
158 {
159 unsigned char buffer[BUFSIZE*32];
160 size_t this_write;
161 FILE *out;
162
163 if (!dst) {
164 fseek(src, len, SEEK_CUR);
165 return;
166 }
167
168 if (!tbz2_stdout) {
169 int fd;
170
171 out = NULL;
172 fd = openat(dir_fd, dst, O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC, 0644);
173 if (fd >= 0)
174 out = fdopen(fd, "w");
175 if (out == NULL)
176 errp("cannot write to '%s'", dst);
177 } else
178 out = stdout;
179
180 do {
181 this_write = fread(buffer, 1, MIN(len, sizeof(buffer)), src);
182 fwrite(buffer, 1, this_write, out);
183 len -= this_write;
184 } while (len && this_write);
185
186 if (out != stdout)
187 fclose(out);
188 }
189
190 static int
191 tbz2_decompose(int dir_fd, const char *tbz2, const char *tarbz2, const char *xpak)
192 {
193 FILE *in;
194 unsigned char tbz2_tail[TBZ2_END_LEN];
195 long xpak_size, tarbz2_size;
196 struct stat st;
197 int ret = 1;
198
199 /* open tbz2 input */
200 in = fopen(tbz2, "r");
201 if (in == NULL)
202 return ret;
203 if (fstat(fileno(in), &st))
204 goto close_in_and_ret;
205
206 if (verbose)
207 printf("input tbz2: %s (%s)\n", tbz2, make_human_readable_str(st.st_size, 1, 0));
208
209 /* verify the tail signature */
210 if (fseek(in, -TBZ2_END_LEN, SEEK_END) != 0)
211 goto close_in_and_ret;
212 if (fread(tbz2_tail, 1, TBZ2_END_LEN, in) != TBZ2_END_LEN)
213 goto close_in_and_ret;
214 if (memcmp(tbz2_tail + 4, TBZ2_END_MSG, TBZ2_END_MSG_LEN)) {
215 warn("%s: Invalid tbz2", tbz2);
216 goto close_in_and_ret;
217 }
218
219 /* calculate xpak's size */
220 xpak_size = tbz2_decode_int(tbz2_tail);
221 /* calculate tarbz2's size */
222 tarbz2_size = st.st_size - xpak_size - TBZ2_END_LEN;
223
224 /* reset to the start of the tbz2 */
225 rewind(in);
226 /* dump the tar.bz2 */
227 if (verbose)
228 printf("output tar.bz2: %s (%s)\n", tarbz2, make_human_readable_str(tarbz2_size, 1, 0));
229 _tbz2_write_file(in, dir_fd, tarbz2, tarbz2_size);
230 /* dump the xpak */
231 if (verbose)
232 printf("output xpak: %s (%s)\n", xpak, make_human_readable_str(xpak_size, 1, 0));
233 _tbz2_write_file(in, dir_fd, xpak, xpak_size);
234
235 ret = 0;
236 close_in_and_ret:
237 fclose(in);
238 return ret;
239 }
240
241 int qtbz2_main(int argc, char **argv)
242 {
243 enum { TBZ2_ACT_NONE, TBZ2_ACT_JOIN, TBZ2_ACT_SPLIT };
244 int i, dir_fd;
245 char action, split_xpak = 1, split_tarbz2 = 1;
246 char *heap_tbz2, *heap_xpak, *heap_tarbz2;
247 char *tbz2, *xpak, *tarbz2;
248
249 DBG("argc=%d argv[0]=%s argv[1]=%s",
250 argc, argv[0], argc > 1 ? argv[1] : "NULL?");
251
252 action = TBZ2_ACT_NONE;
253 dir_fd = AT_FDCWD;
254
255 while ((i = GETOPT_LONG(QTBZ2, qtbz2, "")) != -1) {
256 switch (i) {
257 COMMON_GETOPTS_CASES(qtbz2)
258 case 'j': action = TBZ2_ACT_JOIN; break;
259 case 's': action = TBZ2_ACT_SPLIT; break;
260 case 't': split_xpak = 0; break;
261 case 'x': split_tarbz2 = 0; break;
262 case 'O': tbz2_stdout = 1; break;
263 case 'd':
264 if (dir_fd != AT_FDCWD)
265 err("Only use -d once");
266 dir_fd = open(optarg, O_RDONLY|O_CLOEXEC);
267 break;
268 }
269 }
270 if (optind == argc) {
271 switch (action) {
272 case TBZ2_ACT_JOIN: err("Join usage: <input tar.bz2> <input xpak> [<output tbz2>]");
273 case TBZ2_ACT_SPLIT: err("Split usage: <input tbz2> [<output tar.bz2> <output xpak>]");
274 default: qtbz2_usage(EXIT_FAILURE);
275 }
276 }
277
278 heap_tbz2 = heap_xpak = heap_tarbz2 = NULL;
279 tbz2 = xpak = tarbz2 = NULL;
280
281 if (action == TBZ2_ACT_NONE) {
282 if (strstr(argv[optind], ".tar.bz2") != NULL)
283 action = TBZ2_ACT_JOIN;
284 else if (strstr(argv[optind], ".tbz2") != NULL)
285 action = TBZ2_ACT_SPLIT;
286 else
287 qtbz2_usage(EXIT_FAILURE);
288 }
289
290 /* tbz2tool join .tar.bz2 .xpak .tbz2 */
291 if (action == TBZ2_ACT_JOIN) {
292 /* grab the params if the user gave them */
293 tarbz2 = argv[optind++];
294 if (optind < argc) {
295 xpak = argv[optind++];
296 if (optind < argc)
297 tbz2 = argv[optind];
298 }
299 /* otherwise guess what they should be */
300 if (!xpak || !tbz2) {
301 const char *s = basename(tarbz2);
302 size_t len = strlen(s);
303
304 /* autostrip the tarball extension */
305 if (len >= 8 && !strcmp(s + len - 8, ".tar.bz2"))
306 len -= 8;
307
308 if (!xpak) {
309 xpak = heap_xpak = xmalloc(len + 5 + 1);
310 memcpy(xpak, s, len);
311 strcpy(xpak + len, ".xpak");
312 }
313 if (!tbz2) {
314 tbz2 = heap_tbz2 = xmalloc(len + 5 + 1);
315 memcpy(tbz2, s, len);
316 strcpy(tbz2 + len, ".tbz2");
317 }
318 }
319
320 if (tbz2_compose(dir_fd, tarbz2, xpak, tbz2))
321 warnp("Could not create '%s' from '%s' and '%s'",
322 tbz2, tarbz2, xpak);
323
324 /* tbz2tool split .tbz2 .tar.bz2 .xpak */
325 } else {
326 /* grab the params if the user gave them */
327 tbz2 = argv[optind++];
328 if (optind < argc) {
329 tarbz2 = argv[optind++];
330 if (optind < argc)
331 xpak = argv[optind];
332 }
333 /* otherwise guess what they should be */
334 if ((!tarbz2 && split_tarbz2) || (!xpak && split_xpak)) {
335 const char *s = basename(tbz2);
336 size_t len = strlen(s);
337
338 /* autostrip the package extension */
339 if (len >= 5 && !strcmp(s + len - 5, ".tbz2"))
340 len -= 5;
341
342 if (!tarbz2 && split_tarbz2) {
343 tarbz2 = heap_tarbz2 = xmalloc(len + 8 + 1);
344 memcpy(tarbz2, s, len);
345 strcpy(tarbz2 + len, ".tar.bz2");
346 } else if (!split_tarbz2)
347 tarbz2 = NULL;
348
349 if (!xpak && split_xpak) {
350 xpak = heap_xpak = xmalloc(len + 5 + 1);
351 memcpy(xpak, s, len);
352 strcpy(xpak + len, ".xpak");
353 } else if (!split_xpak)
354 xpak = NULL;
355 }
356
357 if (tbz2_decompose(dir_fd, tbz2, tarbz2, xpak))
358 warn("Could not decompose '%s'", tbz2);
359 }
360
361 free(heap_tbz2);
362 free(heap_xpak);
363 free(heap_tarbz2);
364
365 return EXIT_SUCCESS;
366 }
367
368 #else
369 DEFINE_APPLET_STUB(qtbz2)
370 #endif

  ViewVC Help
Powered by ViewVC 1.1.20