Gentoo Archives: gentoo-commits

From: "Mike Frysinger (vapier)" <vapier@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-projects commit in portage-utils: qpkg.c qtbz2.c qxpak.c
Date: Mon, 28 Feb 2011 18:21:53
Message-Id: 20110228182142.8C91C20054@flycatcher.gentoo.org
1 vapier 11/02/28 18:21:42
2
3 Modified: qpkg.c qtbz2.c qxpak.c
4 Log:
5 redo -d dir option so that it avoids chdir, and redo some of the state so that these applets can be run by other applets
6
7 Revision Changes Path
8 1.34 portage-utils/qpkg.c
9
10 file : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/portage-utils/qpkg.c?rev=1.34&view=markup
11 plain: http://sources.gentoo.org/viewvc.cgi/gentoo-projects/portage-utils/qpkg.c?rev=1.34&content-type=text/plain
12 diff : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/portage-utils/qpkg.c?r1=1.33&r2=1.34
13
14 Index: qpkg.c
15 ===================================================================
16 RCS file: /var/cvsroot/gentoo-projects/portage-utils/qpkg.c,v
17 retrieving revision 1.33
18 retrieving revision 1.34
19 diff -u -r1.33 -r1.34
20 --- qpkg.c 21 Feb 2011 07:38:15 -0000 1.33
21 +++ qpkg.c 28 Feb 2011 18:21:42 -0000 1.34
22 @@ -1,7 +1,7 @@
23 /*
24 * Copyright 2005-2010 Gentoo Foundation
25 * Distributed under the terms of the GNU General Public License v2
26 - * $Header: /var/cvsroot/gentoo-projects/portage-utils/qpkg.c,v 1.33 2011/02/21 07:38:15 vapier Exp $
27 + * $Header: /var/cvsroot/gentoo-projects/portage-utils/qpkg.c,v 1.34 2011/02/28 18:21:42 vapier Exp $
28 *
29 * Copyright 2005-2010 Ned Ludd - <solar@g.o>
30 * Copyright 2005-2010 Mike Frysinger - <vapier@g.o>
31 @@ -24,7 +24,7 @@
32 "alternate package directory",
33 COMMON_OPTS_HELP
34 };
35 -static const char qpkg_rcsid[] = "$Id: qpkg.c,v 1.33 2011/02/21 07:38:15 vapier Exp $";
36 +static const char qpkg_rcsid[] = "$Id: qpkg.c,v 1.34 2011/02/28 18:21:42 vapier Exp $";
37 #define qpkg_usage(ret) usage(ret, QPKG_FLAGS, qpkg_long_opts, qpkg_opts_help, lookup_applet_idx("qpkg"))
38
39 extern char pretend;
40 @@ -268,10 +268,10 @@
41 snprintf(buf, buflen, "%s/%s/%s", portvdb, atom->CATEGORY, atom_to_pvr(atom));
42 xpak_argv[0] = buf;
43 xpak_argv[1] = NULL;
44 - xpak_create(xpak, 1, xpak_argv);
45 + xpak_create(AT_FDCWD, xpak, 1, xpak_argv);
46
47 snprintf(buf, buflen, "%s/binpkg.tbz2", tmpdir);
48 - tbz2_compose(tbz2, xpak, buf);
49 + tbz2_compose(AT_FDCWD, tbz2, xpak, buf);
50
51 unlink(filelist);
52 unlink(xpak);
53
54
55
56 1.18 portage-utils/qtbz2.c
57
58 file : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/portage-utils/qtbz2.c?rev=1.18&view=markup
59 plain: http://sources.gentoo.org/viewvc.cgi/gentoo-projects/portage-utils/qtbz2.c?rev=1.18&content-type=text/plain
60 diff : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/portage-utils/qtbz2.c?r1=1.17&r2=1.18
61
62 Index: qtbz2.c
63 ===================================================================
64 RCS file: /var/cvsroot/gentoo-projects/portage-utils/qtbz2.c,v
65 retrieving revision 1.17
66 retrieving revision 1.18
67 diff -u -r1.17 -r1.18
68 --- qtbz2.c 21 Feb 2011 01:33:47 -0000 1.17
69 +++ qtbz2.c 28 Feb 2011 18:21:42 -0000 1.18
70 @@ -1,7 +1,7 @@
71 /*
72 * Copyright 2005-2010 Gentoo Foundation
73 * Distributed under the terms of the GNU General Public License v2
74 - * $Header: /var/cvsroot/gentoo-projects/portage-utils/qtbz2.c,v 1.17 2011/02/21 01:33:47 vapier Exp $
75 + * $Header: /var/cvsroot/gentoo-projects/portage-utils/qtbz2.c,v 1.18 2011/02/28 18:21:42 vapier Exp $
76 *
77 * Copyright 2005-2010 Ned Ludd - <solar@g.o>
78 * Copyright 2005-2010 Mike Frysinger - <vapier@g.o>
79 @@ -27,8 +27,9 @@
80 #define TBZ2_END_MSG_LEN 4
81 #define TBZ2_END_LEN (4 + TBZ2_END_MSG_LEN)
82
83 -#define QTBZ2_FLAGS "jstxO" COMMON_FLAGS
84 +#define QTBZ2_FLAGS "d:jstxO" COMMON_FLAGS
85 static struct option const qtbz2_long_opts[] = {
86 + {"dir", a_argument, NULL, 'd'},
87 {"join", no_argument, NULL, 'j'},
88 {"split", no_argument, NULL, 's'},
89 {"tarbz2", no_argument, NULL, 't'},
90 @@ -37,6 +38,7 @@
91 COMMON_LONG_OPTS
92 };
93 static const char * const qtbz2_opts_help[] = {
94 + "Change to specified directory",
95 "Join tar.bz2 + xpak into a tbz2",
96 "Split a tbz2 into a tar.bz2 + xpak",
97 "Just split the tar.bz2",
98 @@ -44,7 +46,7 @@
99 "Write files to stdout",
100 COMMON_OPTS_HELP
101 };
102 -static const char qtbz2_rcsid[] = "$Id: qtbz2.c,v 1.17 2011/02/21 01:33:47 vapier Exp $";
103 +static const char qtbz2_rcsid[] = "$Id: qtbz2.c,v 1.18 2011/02/28 18:21:42 vapier Exp $";
104 #define qtbz2_usage(ret) usage(ret, QTBZ2_FLAGS, qtbz2_long_opts, qtbz2_opts_help, lookup_applet_idx("qtbz2"))
105
106 static char tbz2_stdout = 0;
107 @@ -83,28 +85,52 @@
108 }
109 }
110
111 -char tbz2_compose(const char *tarbz2, const char *xpak, const char *tbz2);
112 -char tbz2_compose(const char *tarbz2, const char *xpak, const char *tbz2)
113 +static int
114 +tbz2_compose(int dir_fd, const char *tarbz2, const char *xpak, const char *tbz2)
115 {
116 FILE *out, *in_tarbz2, *in_xpak;
117 struct stat st;
118 - char ret = 1;
119 + int ret = 1, fd;
120 +
121 + if (verbose)
122 + printf("input xpak: %s\ninput tar.bz2: %s\noutput tbz2: %s\n",
123 + xpak, tarbz2, tbz2);
124
125 /* open tbz2 output */
126 if ((out = fopen(tbz2, "w")) == NULL)
127 return ret;
128 /* open tar.bz2 input */
129 - if ((in_tarbz2 = fopen(tarbz2, "r")) == NULL) {
130 + fd = openat(dir_fd, tarbz2, O_RDONLY|O_CLOEXEC);
131 + if (fd < 0) {
132 fclose(out);
133 return ret;
134 }
135 + in_tarbz2 = fdopen(fd, "r");
136 + if (in_tarbz2 == NULL) {
137 + fclose(out);
138 + close(fd);
139 + return ret;
140 + }
141 /* open xpak input */
142 - if ((in_xpak = fopen(xpak, "r")) == NULL) {
143 + fd = openat(dir_fd, xpak, O_RDONLY|O_CLOEXEC);
144 + if (fd < 0) {
145 + fclose(out);
146 + fclose(in_tarbz2);
147 + return ret;
148 + }
149 + in_xpak = fdopen(fd, "r");
150 + if (in_xpak == NULL) {
151 fclose(out);
152 fclose(in_tarbz2);
153 + close(fd);
154 + return ret;
155 + }
156 + if (fstat(fd, &st)) {
157 + fclose(out);
158 + fclose(in_tarbz2);
159 + fclose(in_xpak);
160 return ret;
161 }
162 - fstat(fileno(in_xpak), &st);
163
164 /* save [tarball] */
165 _tbz2_copy_file(in_tarbz2, out);
166 @@ -123,8 +149,8 @@
167 }
168
169 #define _TBZ2_MIN(a,b) (a < b ? : b)
170 -void _tbz2_write_file(FILE *src, const char *dst, size_t len);
171 -void _tbz2_write_file(FILE *src, const char *dst, size_t len)
172 +static void
173 +_tbz2_write_file(FILE *src, int dir_fd, const char *dst, size_t len)
174 {
175 unsigned char buffer[BUFSIZE*32];
176 size_t this_write;
177 @@ -135,10 +161,17 @@
178 return;
179 }
180
181 - if (tbz2_stdout)
182 + if (!tbz2_stdout) {
183 + int fd;
184 +
185 + out = NULL;
186 + fd = openat(dir_fd, dst, O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC, 0644);
187 + if (fd >= 0)
188 + out = fdopen(fd, "w");
189 + if (out == NULL)
190 + errp("cannot write to '%s'", dst);
191 + } else
192 out = stdout;
193 - else if ((out = fopen(dst, "w")) == NULL)
194 - errp("cannot write to '%s'", dst);
195
196 do {
197 this_write = fread(buffer, 1, _TBZ2_MIN(len, sizeof(buffer)), src);
198 @@ -150,19 +183,25 @@
199 fclose(out);
200 }
201
202 -char tbz2_decompose(const char *tbz2, const char *tarbz2, const char *xpak);
203 -char tbz2_decompose(const char *tbz2, const char *tarbz2, const char *xpak)
204 +static int
205 +tbz2_decompose(int dir_fd, const char *tbz2, const char *tarbz2, const char *xpak)
206 {
207 FILE *in;
208 unsigned char tbz2_tail[TBZ2_END_LEN];
209 long xpak_size, tarbz2_size;
210 struct stat st;
211 - char ret = 1;
212 + int ret = 1;
213
214 /* open tbz2 input */
215 - if ((in = fopen(tbz2, "r")) == NULL)
216 + in = fopen(tbz2, "r");
217 + if (in == NULL)
218 return ret;
219 - fstat(fileno(in), &st);
220 + if (fstat(fileno(in), &st))
221 + goto close_in_and_ret;
222 +
223 + if (verbose)
224 + printf("input tbz2: %s (%s)\n", tbz2, make_human_readable_str(st.st_size, 1, 0));
225 +
226 /* verify the tail signature */
227 if (fseek(in, -TBZ2_END_LEN, SEEK_END) != 0)
228 goto close_in_and_ret;
229 @@ -181,60 +220,71 @@
230 /* reset to the start of the tbz2 */
231 rewind(in);
232 /* dump the tar.bz2 */
233 - _tbz2_write_file(in, tarbz2, tarbz2_size);
234 + if (verbose)
235 + printf("output tar.bz2: %s (%s)\n", tarbz2, make_human_readable_str(tarbz2_size, 1, 0));
236 + _tbz2_write_file(in, dir_fd, tarbz2, tarbz2_size);
237 /* dump the xpak */
238 - _tbz2_write_file(in, xpak, xpak_size);
239 + if (verbose)
240 + printf("output xpak: %s (%s)\n", xpak, make_human_readable_str(xpak_size, 1, 0));
241 + _tbz2_write_file(in, dir_fd, xpak, xpak_size);
242
243 ret = 0;
244 -close_in_and_ret:
245 + close_in_and_ret:
246 fclose(in);
247 return ret;
248 }
249
250 int qtbz2_main(int argc, char **argv)
251 {
252 - int i;
253 - char action = 0, split_xpak = 1, split_tarbz2 = 1;
254 + enum { TBZ2_ACT_NONE, TBZ2_ACT_JOIN, TBZ2_ACT_SPLIT };
255 + int i, dir_fd;
256 + char action, split_xpak = 1, split_tarbz2 = 1;
257 char *heap_tbz2, *heap_xpak, *heap_tarbz2;
258 char *tbz2, *xpak, *tarbz2;
259
260 DBG("argc=%d argv[0]=%s argv[1]=%s",
261 argc, argv[0], argc > 1 ? argv[1] : "NULL?");
262
263 + action = TBZ2_ACT_NONE;
264 + dir_fd = AT_FDCWD;
265 +
266 while ((i = GETOPT_LONG(QTBZ2, qtbz2, "")) != -1) {
267 switch (i) {
268 COMMON_GETOPTS_CASES(qtbz2)
269 - case 'j': action = 1; break;
270 - case 's': action = 2; break;
271 + case 'j': action = TBZ2_ACT_JOIN; break;
272 + case 's': action = TBZ2_ACT_SPLIT; break;
273 case 't': split_xpak = 0; break;
274 case 'x': split_tarbz2 = 0; break;
275 case 'O': tbz2_stdout = 1; break;
276 + case 'd':
277 + if (dir_fd != AT_FDCWD)
278 + err("Only use -d once");
279 + dir_fd = open(optarg, O_RDONLY|O_CLOEXEC);
280 + break;
281 }
282 }
283 if (optind == argc) {
284 switch (action) {
285 - case 1: join_usage:
286 - err("Join usage: <input tar.bz2> <input xpak> [<output tbz2>]");
287 - case 2: split_usage:
288 - err("Split usage <input tbz2> [<output tar.bz2> <output xpak>]");
289 - default: qtbz2_usage(EXIT_FAILURE);
290 + case TBZ2_ACT_JOIN: err("Join usage: <input tar.bz2> <input xpak> [<output tbz2>]");
291 + case TBZ2_ACT_SPLIT: err("Split usage: <input tbz2> [<output tar.bz2> <output xpak>]");
292 + default: qtbz2_usage(EXIT_FAILURE);
293 }
294 }
295
296 heap_tbz2 = heap_xpak = heap_tarbz2 = NULL;
297 tbz2 = xpak = tarbz2 = NULL;
298
299 - if (action == 0) {
300 + if (action == TBZ2_ACT_NONE) {
301 if (strstr(argv[optind], ".tar.bz2") != NULL)
302 - action = 1;
303 + action = TBZ2_ACT_JOIN;
304 else if (strstr(argv[optind], ".tbz2") != NULL)
305 - action = 2;
306 + action = TBZ2_ACT_SPLIT;
307 else
308 qtbz2_usage(EXIT_FAILURE);
309 }
310
311 /* tbz2tool join .tar.bz2 .xpak .tbz2 */
312 - if (action == 1) {
313 + if (action == TBZ2_ACT_JOIN) {
314 /* grab the params if the user gave them */
315 tarbz2 = argv[optind++];
316 if (optind < argc) {
317 @@ -243,20 +293,27 @@
318 tbz2 = argv[optind];
319 }
320 /* otherwise guess what they should be */
321 - if (!xpak) {
322 - i = strlen(tarbz2);
323 - if (i <= 5) goto join_usage;
324 - xpak = heap_xpak = xstrdup(tarbz2);
325 - strcpy(xpak+i-7, "xpak");
326 - }
327 - if (!tbz2) {
328 - i = strlen(tarbz2);
329 - if (i <= 5) goto join_usage;
330 - tbz2 = heap_tbz2 = xstrdup(tarbz2);
331 - strcpy(tbz2+i-6, "bz2");
332 + if (!xpak || !tbz2) {
333 + const char *s = basename(tarbz2);
334 + size_t len = strlen(s);
335 +
336 + /* autostrip the tarball extension */
337 + if (len >= 8 && !strcmp(s + len - 8, ".tar.bz2"))
338 + len -= 8;
339 +
340 + if (!xpak) {
341 + xpak = heap_xpak = xmalloc(len + 5 + 1);
342 + memcpy(xpak, s, len);
343 + strcpy(xpak + len, ".xpak");
344 + }
345 + if (!tbz2) {
346 + tbz2 = heap_tbz2 = xmalloc(len + 5 + 1);
347 + memcpy(tbz2, s, len);
348 + strcpy(tbz2 + len, ".tbz2");
349 + }
350 }
351
352 - if (tbz2_compose(tarbz2, xpak, tbz2))
353 + if (tbz2_compose(dir_fd, tarbz2, xpak, tbz2))
354 warn("Could not compose '%s' and '%s'", tarbz2, xpak);
355
356 /* tbz2tool split .tbz2 .tar.bz2 .xpak */
357 @@ -269,29 +326,36 @@
358 xpak = argv[optind];
359 }
360 /* otherwise guess what they should be */
361 - if (!tarbz2 && split_tarbz2) {
362 - i = strlen(tbz2);
363 - if (i <= 5) goto split_usage;
364 - tarbz2 = heap_tarbz2 = xmalloc(i + 4);
365 - strcpy(tarbz2, tbz2);
366 - strcpy(tarbz2+i-3, "ar.bz2");
367 - } else if (!split_tarbz2)
368 - tarbz2 = NULL;
369 - if (!xpak && split_xpak) {
370 - i = strlen(tbz2);
371 - if (i <= 5) goto split_usage;
372 - xpak = heap_xpak = xstrdup(tbz2);
373 - strcpy(xpak+i-4, "xpak");
374 - } else if (!split_xpak)
375 - xpak = NULL;
376 + if ((!tarbz2 && split_tarbz2) || (!xpak && split_xpak)) {
377 + const char *s = basename(tbz2);
378 + size_t len = strlen(s);
379 +
380 + /* autostrip the package extension */
381 + if (len >= 5 && !strcmp(s + len - 5, ".tbz2"))
382 + len -= 5;
383 +
384 + if (!tarbz2 && split_tarbz2) {
385 + tarbz2 = heap_tarbz2 = xmalloc(len + 8 + 1);
386 + memcpy(tarbz2, s, len);
387 + strcpy(tarbz2 + len, ".tar.bz2");
388 + } else if (!split_tarbz2)
389 + tarbz2 = NULL;
390 +
391 + if (!xpak && split_xpak) {
392 + xpak = heap_xpak = xmalloc(len + 5 + 1);
393 + memcpy(xpak, s, len);
394 + strcpy(xpak + len, ".xpak");
395 + } else if (!split_xpak)
396 + xpak = NULL;
397 + }
398
399 - if (tbz2_decompose(tbz2, tarbz2, xpak))
400 + if (tbz2_decompose(dir_fd, tbz2, tarbz2, xpak))
401 warn("Could not decompose '%s'", tbz2);
402 }
403
404 - if (heap_tbz2) free(heap_tbz2);
405 - if (heap_xpak) free(heap_xpak);
406 - if (heap_tarbz2) free(heap_tarbz2);
407 + free(heap_tbz2);
408 + free(heap_xpak);
409 + free(heap_tarbz2);
410
411 return EXIT_SUCCESS;
412 }
413
414
415
416 1.22 portage-utils/qxpak.c
417
418 file : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/portage-utils/qxpak.c?rev=1.22&view=markup
419 plain: http://sources.gentoo.org/viewvc.cgi/gentoo-projects/portage-utils/qxpak.c?rev=1.22&content-type=text/plain
420 diff : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/portage-utils/qxpak.c?r1=1.21&r2=1.22
421
422 Index: qxpak.c
423 ===================================================================
424 RCS file: /var/cvsroot/gentoo-projects/portage-utils/qxpak.c,v
425 retrieving revision 1.21
426 retrieving revision 1.22
427 diff -u -r1.21 -r1.22
428 --- qxpak.c 21 Feb 2011 01:33:47 -0000 1.21
429 +++ qxpak.c 28 Feb 2011 18:21:42 -0000 1.22
430 @@ -1,7 +1,7 @@
431 /*
432 * Copyright 2005-2010 Gentoo Foundation
433 * Distributed under the terms of the GNU General Public License v2
434 - * $Header: /var/cvsroot/gentoo-projects/portage-utils/qxpak.c,v 1.21 2011/02/21 01:33:47 vapier Exp $
435 + * $Header: /var/cvsroot/gentoo-projects/portage-utils/qxpak.c,v 1.22 2011/02/28 18:21:42 vapier Exp $
436 *
437 * Copyright 2005-2010 Ned Ludd - <solar@g.o>
438 * Copyright 2005-2010 Mike Frysinger - <vapier@g.o>
439 @@ -46,21 +46,22 @@
440 "Write files to stdout",
441 COMMON_OPTS_HELP
442 };
443 -static const char qxpak_rcsid[] = "$Id: qxpak.c,v 1.21 2011/02/21 01:33:47 vapier Exp $";
444 +static const char qxpak_rcsid[] = "$Id: qxpak.c,v 1.22 2011/02/28 18:21:42 vapier Exp $";
445 #define qxpak_usage(ret) usage(ret, QXPAK_FLAGS, qxpak_long_opts, qxpak_opts_help, lookup_applet_idx("qxpak"))
446
447 typedef struct {
448 + int dir_fd;
449 FILE *fp;
450 int index_len;
451 int data_len;
452 char *index, *data;
453 } _xpak_archive;
454
455 -static char *xpak_chdir = NULL;
456 -static char xpak_stdout = 0;
457 +static char xpak_stdout;
458
459 -void _xpak_walk_index(_xpak_archive *x, int argc, char **argv, void (*func)(char*,int,int,int,char*));
460 -void _xpak_walk_index(_xpak_archive *x, int argc, char **argv, void (*func)(char*,int,int,int,char*))
461 +typedef void (*xpak_callback_t)(int,char*,int,int,int,char*);
462 +
463 +static void _xpak_walk_index(_xpak_archive *x, int argc, char **argv, xpak_callback_t func)
464 {
465 int i, pathname_len, data_offset, data_len;
466 char *p, pathname[100];
467 @@ -88,7 +89,7 @@
468 if (i == argc)
469 continue;
470 }
471 - (*func)(pathname, pathname_len, data_offset, data_len, x->data);
472 + (*func)(x->dir_fd, pathname, pathname_len, data_offset, data_len, x->data);
473 }
474
475 if (argc)
476 @@ -97,8 +98,7 @@
477 warn("Could not locate '%s' in archive", argv[i]);
478 }
479
480 -_xpak_archive *_xpak_open(const char *file);
481 -_xpak_archive *_xpak_open(const char *file)
482 +static _xpak_archive *_xpak_open(const char *file)
483 {
484 static _xpak_archive ret;
485 char buf[XPAK_START_LEN];
486 @@ -126,10 +126,6 @@
487 goto close_and_ret;
488 }
489
490 - /* clean up before returning */
491 - if (xpak_chdir)
492 - xchdir(xpak_chdir);
493 -
494 return &ret;
495
496 close_and_ret:
497 @@ -138,14 +134,14 @@
498 return NULL;
499 }
500
501 -void _xpak_close(_xpak_archive *x);
502 -void _xpak_close(_xpak_archive *x)
503 +static void _xpak_close(_xpak_archive *x)
504 {
505 fclose(x->fp);
506 }
507
508 -void _xpak_list_callback(char *pathname, _q_unused_ int pathname_len, int data_offset, int data_len, _q_unused_ char *data);
509 -void _xpak_list_callback(char *pathname, _q_unused_ int pathname_len, int data_offset, int data_len, _q_unused_ char *data)
510 +static void
511 +_xpak_list_callback(int dir_fd, char *pathname, _q_unused_ int pathname_len,
512 + int data_offset, int data_len, _q_unused_ char *data)
513 {
514 if (!verbose)
515 puts(pathname);
516 @@ -155,52 +151,65 @@
517 printf("%s: %i byte%c @ offset byte %i\n",
518 pathname, data_len, (data_len>1?'s':' '), data_offset);
519 }
520 -void xpak_list(const char *file, int argc, char **argv);
521 -void xpak_list(const char *file, int argc, char **argv)
522 +static int
523 +xpak_list(int dir_fd, const char *file, int argc, char **argv)
524 {
525 _xpak_archive *x;
526 char buf[BUFSIZE];
527
528 x = _xpak_open(file);
529 - if (!x) return;
530 + if (!x)
531 + return 1;
532
533 + x->dir_fd = dir_fd;
534 x->index = buf;
535 assert((size_t)x->index_len < sizeof(buf));
536 assert(fread(x->index, 1, x->index_len, x->fp) == (size_t)x->index_len);
537 _xpak_walk_index(x, argc, argv, &_xpak_list_callback);
538
539 _xpak_close(x);
540 +
541 + return 0;
542 }
543
544 -void _xpak_extract_callback(char *pathname, _q_unused_ int pathname_len, int data_offset, int data_len, char *data);
545 -void _xpak_extract_callback(char *pathname, _q_unused_ int pathname_len, int data_offset, int data_len, char *data)
546 +static void
547 +_xpak_extract_callback(int dir_fd, char *pathname, _q_unused_ int pathname_len,
548 + int data_offset, int data_len, char *data)
549 {
550 FILE *out;
551 +
552 if (verbose == 1)
553 puts(pathname);
554 else if (verbose > 1)
555 printf("%s: %i byte%c\n", pathname, data_len, (data_len>1?'s':' '));
556 - if (xpak_stdout)
557 +
558 + if (!xpak_stdout) {
559 + int fd = openat(dir_fd, pathname, O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC, 0644);
560 + if (fd < 0)
561 + return;
562 + out = fdopen(fd, "w");
563 + if (!out)
564 + return;
565 + } else
566 out = stdout;
567 - else if ((out = fopen(pathname, "w")) == NULL)
568 - return;
569 - fwrite(data+data_offset, 1, data_len, out);
570 +
571 + fwrite(data + data_offset, 1, data_len, out);
572 +
573 if (!xpak_stdout)
574 fclose(out);
575 }
576 -void xpak_extract(const char *file, int argc, char **argv);
577 -void xpak_extract(const char *file, int argc, char **argv)
578 +static int
579 +xpak_extract(int dir_fd, const char *file, int argc, char **argv)
580 {
581 _xpak_archive *x;
582 char buf[BUFSIZE], ext[BUFSIZE*32];
583 size_t in;
584
585 - if (argc == 0)
586 - err("Extract usage: <xpak output> <files/dirs to extract>");
587 -
588 x = _xpak_open(file);
589 - if (!x) return;
590 + if (!x)
591 + return 1;
592
593 + x->dir_fd = dir_fd;
594 x->index = buf;
595
596 assert((size_t)x->index_len < sizeof(buf));
597 @@ -220,15 +229,18 @@
598
599 if (x->data != ext)
600 free(x->data);
601 +
602 + return 0;
603 }
604
605 -void _xpak_add_file(const char *filename, struct stat *st, FILE *findex, int *index_len, FILE *fdata, int *data_len);
606 -void _xpak_add_file(const char *filename, struct stat *st, FILE *findex, int *index_len, FILE *fdata, int *data_len)
607 +static void
608 +_xpak_add_file(int dir_fd, const char *filename, struct stat *st, FILE *findex,
609 + int *index_len, FILE *fdata, int *data_len)
610 {
611 FILE *fin;
612 unsigned char *p;
613 const char *basefile;
614 - int in_len;
615 + int fd, in_len;
616
617 if ((basefile = strrchr(filename, '/')) == NULL) {
618 basefile = filename;
619 @@ -255,13 +267,20 @@
620 *index_len += 4 + in_len + 4 + 4;
621
622 /* now open the file, get (data_len), and append the file to the data file */
623 - if ((fin = fopen(filename, "r")) == NULL) {
624 - warnp("Could not open '%s' for reading", filename);
625 -fake_data_len:
626 + fd = openat(dir_fd, filename, O_RDONLY|O_CLOEXEC);
627 + if (fd < 0) {
628 + open_fail:
629 + warnp("could not open for reading: %s", filename);
630 + fake_data_len:
631 p = tbz2_encode_int(0);
632 fwrite(p, 1, 4, findex);
633 return;
634 }
635 + fin = fdopen(fd, "r");
636 + if (!fin) {
637 + close(fd);
638 + goto open_fail;
639 + }
640 in_len = st->st_size;
641 /* the xpak format can only store files whose size is a 32bit int
642 * so we have to make sure we don't store a big file */
643 @@ -277,8 +296,8 @@
644
645 *data_len += in_len;
646 }
647 -void xpak_create(const char *file, int argc, char **argv);
648 -void xpak_create(const char *file, int argc, char **argv)
649 +static int
650 +xpak_create(int dir_fd, const char *file, int argc, char **argv)
651 {
652 FILE *findex, *fdata, *fout;
653 struct dirent **dir;
654 @@ -294,35 +313,42 @@
655 if (strlen(file) >= sizeof(path)-6)
656 err("Pathname is too long: %s", file);
657
658 - if ((fout = fopen(file, "w")) == NULL)
659 - return;
660 + if ((fout = fopen(file, "w")) == NULL) {
661 + warnp("could not open output: %s", file);
662 + return 1;
663 + }
664 strcpy(path, file); strcat(path, ".index");
665 if ((findex = fopen(path, "w+")) == NULL) {
666 + warnp("could not open output: %s", path);
667 fclose(fout);
668 - return;
669 + return 1;
670 }
671 strcpy(path, file); strcat(path, ".dat");
672 if ((fdata = fopen(path, "w+")) == NULL) {
673 + warnp("could not open output: %s", path);
674 fclose(fout);
675 fclose(findex);
676 - return;
677 + return 1;
678 }
679
680 index_len = data_len = 0;
681 for (i = 0; i < argc; ++i) {
682 - stat(argv[i], &st);
683 + if (fstatat(dir_fd, argv[i], &st, 0)) {
684 + warnp("fstatat(%s) failed", argv[i]);
685 + continue;
686 + }
687 if (S_ISDIR(st.st_mode)) {
688 if ((numfiles = scandir(argv[i], &dir, filter_hidden, alphasort)) < 0)
689 warn("Directory '%s' is empty; skipping", argv[i]);
690 for (fidx = 0; fidx < numfiles; ++fidx) {
691 snprintf(path, sizeof(path), "%s/%s", argv[i], dir[fidx]->d_name);
692 stat(path, &st);
693 - _xpak_add_file(path, &st, findex, &index_len, fdata, &data_len);
694 + _xpak_add_file(dir_fd, path, &st, findex, &index_len, fdata, &data_len);
695 }
696 while (numfiles--) free(dir[numfiles]);
697 free(dir);
698 } else if (S_ISREG(st.st_mode)) {
699 - _xpak_add_file(argv[i], &st, findex, &index_len, fdata, &data_len);
700 + _xpak_add_file(dir_fd, argv[i], &st, findex, &index_len, fdata, &data_len);
701 } else
702 warn("Skipping non file/directory '%s'", argv[i]);
703 }
704 @@ -345,18 +371,23 @@
705 fclose(findex);
706 fclose(fdata);
707 fclose(fout);
708 +
709 + return 0;
710 }
711
712 int qxpak_main(int argc, char **argv)
713 {
714 enum { XPAK_ACT_NONE, XPAK_ACT_LIST, XPAK_ACT_EXTRACT, XPAK_ACT_CREATE };
715 - int i;
716 + int i, ret, dir_fd;
717 char *xpak;
718 char action = XPAK_ACT_NONE;
719
720 DBG("argc=%d argv[0]=%s argv[1]=%s",
721 argc, argv[0], argc > 1 ? argv[1] : "NULL?");
722
723 + dir_fd = AT_FDCWD;
724 + xpak_stdout = 0;
725 +
726 while ((i = GETOPT_LONG(QXPAK, qxpak, "")) != -1) {
727 switch (i) {
728 COMMON_GETOPTS_CASES(qxpak)
729 @@ -365,8 +396,9 @@
730 case 'c': action = XPAK_ACT_CREATE; break;
731 case 'O': xpak_stdout = 1; break;
732 case 'd':
733 - if (xpak_chdir) err("Only use -d once");
734 - xpak_chdir = xstrdup(optarg);
735 + if (dir_fd != AT_FDCWD)
736 + err("Only use -d once");
737 + dir_fd = open(optarg, O_RDONLY|O_CLOEXEC);
738 break;
739 }
740 }
741 @@ -378,14 +410,16 @@
742 argv += optind;
743
744 switch (action) {
745 - case XPAK_ACT_LIST: xpak_list(xpak, argc, argv); break;
746 - case XPAK_ACT_EXTRACT: xpak_extract(xpak, argc, argv); break;
747 - case XPAK_ACT_CREATE: xpak_create(xpak, argc, argv); break;
748 + case XPAK_ACT_LIST: ret = xpak_list(dir_fd, xpak, argc, argv); break;
749 + case XPAK_ACT_EXTRACT: ret = xpak_extract(dir_fd, xpak, argc, argv); break;
750 + case XPAK_ACT_CREATE: ret = xpak_create(dir_fd, xpak, argc, argv); break;
751 + default: ret = EXIT_FAILURE;
752 }
753
754 - if (xpak_chdir) free(xpak_chdir);
755 + if (dir_fd != AT_FDCWD)
756 + close(dir_fd);
757
758 - return EXIT_SUCCESS;
759 + return ret;
760 }
761
762 #else