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 |