1 |
commit: 5ec1f4368412c8d6f02148d3d9cb109050c8c626 |
2 |
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
3 |
AuthorDate: Fri Nov 15 13:50:10 2019 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Fri Nov 15 13:50:10 2019 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=5ec1f436 |
7 |
|
8 |
libq/xpak: rework to reuse more code |
9 |
|
10 |
- introduce xpak_process{,_fd} to replace the very similar list and extract |
11 |
- add _fd variant to be able to pass already open filedescriptor |
12 |
- rework interface to carry a context pointer for the callback func for |
13 |
more flexibility |
14 |
- adapt qxpak for the interface changes |
15 |
|
16 |
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> |
17 |
|
18 |
libq/xpak.c | 132 ++++++++++++++++++++++++++---------------------------------- |
19 |
libq/xpak.h | 26 +++--------- |
20 |
qxpak.c | 98 ++++++++++++++++++++++++++------------------ |
21 |
3 files changed, 120 insertions(+), 136 deletions(-) |
22 |
|
23 |
diff --git a/libq/xpak.c b/libq/xpak.c |
24 |
index c2e93f9..9692eab 100644 |
25 |
--- a/libq/xpak.c |
26 |
+++ b/libq/xpak.c |
27 |
@@ -39,23 +39,22 @@ |
28 |
#define XPAK_END_MSG_LEN 8 |
29 |
|
30 |
typedef struct { |
31 |
- int dir_fd; |
32 |
+ void *ctx; |
33 |
FILE *fp; |
34 |
- int index_len; |
35 |
- int data_len; |
36 |
+ unsigned int index_len; |
37 |
+ unsigned int data_len; |
38 |
char *index, *data; |
39 |
} _xpak_archive; |
40 |
|
41 |
-typedef void (*xpak_callback_t)(int,char*,int,int,int,char*); |
42 |
- |
43 |
static void _xpak_walk_index( |
44 |
_xpak_archive *x, |
45 |
- int argc, |
46 |
- char **argv, |
47 |
xpak_callback_t func) |
48 |
{ |
49 |
- int i, pathname_len, data_offset, data_len; |
50 |
- char *p, pathname[100]; |
51 |
+ unsigned int pathname_len; |
52 |
+ unsigned int data_offset; |
53 |
+ unsigned int data_len; |
54 |
+ char *p; |
55 |
+ char pathname[100]; |
56 |
|
57 |
p = x->index; |
58 |
while ((p - x->index) < x->index_len) { |
59 |
@@ -73,43 +72,26 @@ static void _xpak_walk_index( |
60 |
p += 4; |
61 |
data_len = READ_BE_INT32((unsigned char*)p); |
62 |
p += 4; |
63 |
- if (argc) { |
64 |
- for (i = 0; i < argc; ++i) { |
65 |
- if (argv[i] && !strcmp(pathname, argv[i])) { |
66 |
- argv[i] = NULL; |
67 |
- break; |
68 |
- } |
69 |
- } |
70 |
- if (i == argc) |
71 |
- continue; |
72 |
- } |
73 |
- (*func)(x->dir_fd, pathname, pathname_len, |
74 |
+ (*func)(x->ctx, pathname, pathname_len, |
75 |
data_offset, data_len, x->data); |
76 |
} |
77 |
- |
78 |
- if (argc) |
79 |
- for (i = 0; i < argc; ++i) |
80 |
- if (argv[i]) |
81 |
- warn("Could not locate '%s' in archive", argv[i]); |
82 |
} |
83 |
|
84 |
-static _xpak_archive *_xpak_open(const char *file) |
85 |
+static _xpak_archive *_xpak_open(const int fd) |
86 |
{ |
87 |
static _xpak_archive ret; |
88 |
char buf[XPAK_START_LEN]; |
89 |
|
90 |
/* init the file */ |
91 |
memset(&ret, 0x00, sizeof(ret)); |
92 |
- if (file[0] == '-' && file[1] == '\0') |
93 |
- ret.fp = stdin; |
94 |
- else if ((ret.fp = fopen(file, "r")) == NULL) |
95 |
+ if ((ret.fp = fdopen(fd, "r")) == NULL) |
96 |
return NULL; |
97 |
|
98 |
/* verify this xpak doesnt suck */ |
99 |
if (fread(buf, 1, XPAK_START_LEN, ret.fp) != XPAK_START_LEN) |
100 |
goto close_and_ret; |
101 |
if (memcmp(buf, XPAK_START_MSG, XPAK_START_MSG_LEN)) { |
102 |
- warn("%s: Invalid xpak", file); |
103 |
+ warn("Not an xpak file"); |
104 |
goto close_and_ret; |
105 |
} |
106 |
|
107 |
@@ -117,7 +99,7 @@ static _xpak_archive *_xpak_open(const char *file) |
108 |
ret.index_len = READ_BE_INT32((unsigned char*)buf+XPAK_START_MSG_LEN); |
109 |
ret.data_len = READ_BE_INT32((unsigned char*)buf+XPAK_START_MSG_LEN+4); |
110 |
if (!ret.index_len || !ret.data_len) { |
111 |
- warn("Skipping empty archive '%s'", file); |
112 |
+ warn("Skipping empty archive"); |
113 |
goto close_and_ret; |
114 |
} |
115 |
|
116 |
@@ -135,52 +117,21 @@ static void _xpak_close(_xpak_archive *x) |
117 |
} |
118 |
|
119 |
int |
120 |
-xpak_list( |
121 |
- int dir_fd, |
122 |
- const char *file, |
123 |
- int argc, |
124 |
- char **argv, |
125 |
- xpak_callback_t func) |
126 |
-{ |
127 |
- _xpak_archive *x; |
128 |
- char buf[BUFSIZE]; |
129 |
- size_t ret; |
130 |
- |
131 |
- x = _xpak_open(file); |
132 |
- if (!x) |
133 |
- return 1; |
134 |
- |
135 |
- x->dir_fd = dir_fd; |
136 |
- x->index = buf; |
137 |
- if (x->index_len >= sizeof(buf)) |
138 |
- err("index length %d exceeds limit %zd", x->index_len, sizeof(buf)); |
139 |
- ret = fread(x->index, 1, x->index_len, x->fp); |
140 |
- if (ret != (size_t)x->index_len) |
141 |
- err("insufficient data read, got %zd, requested %d", ret, x->index_len); |
142 |
- _xpak_walk_index(x, argc, argv, func); |
143 |
- |
144 |
- _xpak_close(x); |
145 |
- |
146 |
- return 0; |
147 |
-} |
148 |
- |
149 |
-int |
150 |
-xpak_extract( |
151 |
- int dir_fd, |
152 |
- const char *file, |
153 |
- int argc, |
154 |
- char **argv, |
155 |
+xpak_process_fd( |
156 |
+ int fd, |
157 |
+ bool get_data, |
158 |
+ void *ctx, |
159 |
xpak_callback_t func) |
160 |
{ |
161 |
_xpak_archive *x; |
162 |
char buf[BUFSIZE], ext[BUFSIZE*32]; |
163 |
size_t in; |
164 |
|
165 |
- x = _xpak_open(file); |
166 |
+ x = _xpak_open(fd); |
167 |
if (!x) |
168 |
return 1; |
169 |
|
170 |
- x->dir_fd = dir_fd; |
171 |
+ x->ctx = ctx; |
172 |
x->index = buf; |
173 |
|
174 |
if (x->index_len >= sizeof(buf)) |
175 |
@@ -189,22 +140,51 @@ xpak_extract( |
176 |
if (in != (size_t)x->index_len) |
177 |
err("insufficient data read, got %zd, requested %d", in, x->index_len); |
178 |
|
179 |
- /* the xpak may be large (like when it has CONTENTS) #300744 */ |
180 |
- x->data = (size_t)x->data_len < sizeof(ext) ? ext : xmalloc(x->data_len); |
181 |
- in = fread(x->data, 1, x->data_len, x->fp); |
182 |
- if (in != (size_t)x->data_len) |
183 |
- err("insufficient data read, got %zd, requested %d", in, x->data_len); |
184 |
+ if (get_data) { |
185 |
+ /* the xpak may be large (like when it has CONTENTS) #300744 */ |
186 |
+ x->data = (size_t)x->data_len < sizeof(ext) ? |
187 |
+ ext : xmalloc(x->data_len); |
188 |
+ in = fread(x->data, 1, x->data_len, x->fp); |
189 |
+ if (in != (size_t)x->data_len) |
190 |
+ err("insufficient data read, got %zd, requested %d", |
191 |
+ in, x->data_len); |
192 |
+ } else { |
193 |
+ x->data = NULL; |
194 |
+ x->data_len = 0; |
195 |
+ } |
196 |
|
197 |
- _xpak_walk_index(x, argc, argv, func); |
198 |
+ _xpak_walk_index(x, func); |
199 |
|
200 |
_xpak_close(x); |
201 |
|
202 |
- if (x->data != ext) |
203 |
+ if (get_data && x->data != ext) |
204 |
free(x->data); |
205 |
|
206 |
return 0; |
207 |
} |
208 |
|
209 |
+int |
210 |
+xpak_process( |
211 |
+ const char *file, |
212 |
+ bool get_data, |
213 |
+ void *ctx, |
214 |
+ xpak_callback_t func) |
215 |
+{ |
216 |
+ int fd = -1; |
217 |
+ int ret; |
218 |
+ |
219 |
+ if (file[0] == '-' && file[1] == '\0') |
220 |
+ fd = 0; |
221 |
+ else if ((fd = open(file, O_RDONLY | O_CLOEXEC)) == -1) |
222 |
+ return -1; |
223 |
+ |
224 |
+ ret = xpak_process_fd(fd, get_data, ctx, func); |
225 |
+ if (ret != 0) |
226 |
+ warn("Unable to open file '%s'", file); |
227 |
+ |
228 |
+ return ret; |
229 |
+} |
230 |
+ |
231 |
static void |
232 |
_xpak_add_file( |
233 |
int dir_fd, |
234 |
@@ -279,7 +259,7 @@ xpak_create( |
235 |
const char *file, |
236 |
int argc, |
237 |
char **argv, |
238 |
- char append, |
239 |
+ bool append, |
240 |
int verbose) |
241 |
{ |
242 |
FILE *findex, *fdata, *fout; |
243 |
|
244 |
diff --git a/libq/xpak.h b/libq/xpak.h |
245 |
index 0b318b2..aeafdae 100644 |
246 |
--- a/libq/xpak.h |
247 |
+++ b/libq/xpak.h |
248 |
@@ -6,26 +6,12 @@ |
249 |
#ifndef _XPAK_H |
250 |
#define _XPAK_H 1 |
251 |
|
252 |
-typedef void (*xpak_callback_t)(int,char*,int,int,int,char*); |
253 |
+typedef void (*xpak_callback_t)(void *, char *, int, int, int, char *); |
254 |
|
255 |
-int xpak_list( |
256 |
- int dir_fd, |
257 |
- const char *file, |
258 |
- int argc, |
259 |
- char **argv, |
260 |
- xpak_callback_t func); |
261 |
-int xpak_extract( |
262 |
- int dir_fd, |
263 |
- const char *file, |
264 |
- int argc, |
265 |
- char **argv, |
266 |
- xpak_callback_t func); |
267 |
-int xpak_create( |
268 |
- int dir_fd, |
269 |
- const char *file, |
270 |
- int argc, |
271 |
- char **argv, |
272 |
- char append, |
273 |
- int v); |
274 |
+int xpak_process_fd(int, bool, void *, xpak_callback_t); |
275 |
+int xpak_process(const char *, bool, void *, xpak_callback_t); |
276 |
+#define xpak_list(A,B,C) xpak_process(A,false,B,C) |
277 |
+#define xpak_extract(A,B,C) xpak_process(A,true,B,C) |
278 |
+int xpak_create(int, const char *, int, char **, bool, int); |
279 |
|
280 |
#endif |
281 |
|
282 |
diff --git a/qxpak.c b/qxpak.c |
283 |
index eb19cae..fd0ec5d 100644 |
284 |
--- a/qxpak.c |
285 |
+++ b/qxpak.c |
286 |
@@ -42,31 +42,16 @@ static const char * const qxpak_opts_help[] = { |
287 |
|
288 |
static char xpak_stdout; |
289 |
|
290 |
-static void |
291 |
-_xpak_list_callback( |
292 |
- int dir_fd, |
293 |
- char *pathname, |
294 |
- int pathname_len, |
295 |
- int data_offset, |
296 |
- int data_len, |
297 |
- char *data) |
298 |
-{ |
299 |
- (void)dir_fd; |
300 |
- (void)pathname_len; |
301 |
- (void)data; |
302 |
- |
303 |
- if (!verbose) |
304 |
- puts(pathname); |
305 |
- else if (verbose == 1) |
306 |
- printf("%s: %i byte%c\n", pathname, data_len, (data_len>1?'s':' ')); |
307 |
- else |
308 |
- printf("%s: %i byte%c @ offset byte %i\n", |
309 |
- pathname, data_len, (data_len>1?'s':' '), data_offset); |
310 |
-} |
311 |
+struct qxpak_cb { |
312 |
+ int dir_fd; |
313 |
+ int argc; |
314 |
+ char **argv; |
315 |
+ bool extract; |
316 |
+}; |
317 |
|
318 |
static void |
319 |
-_xpak_extract_callback( |
320 |
- int dir_fd, |
321 |
+_xpak_callback( |
322 |
+ void *ctx, |
323 |
char *pathname, |
324 |
int pathname_len, |
325 |
int data_offset, |
326 |
@@ -74,16 +59,38 @@ _xpak_extract_callback( |
327 |
char *data) |
328 |
{ |
329 |
FILE *out; |
330 |
- (void)pathname_len; |
331 |
+ struct qxpak_cb *xctx = (struct qxpak_cb *)ctx; |
332 |
+ |
333 |
+ /* see if there is a match when there is a selection */ |
334 |
+ if (xctx->argc > 0) { |
335 |
+ int i; |
336 |
+ for (i = 0; i < xctx->argc; i++) { |
337 |
+ if (xctx->argv[i] && !strcmp(pathname, xctx->argv[i])) { |
338 |
+ xctx->argv[i] = NULL; |
339 |
+ break; |
340 |
+ } |
341 |
+ } |
342 |
+ if (i == xctx->argc) |
343 |
+ return; |
344 |
+ } |
345 |
|
346 |
- if (verbose == 1) |
347 |
- puts(pathname); |
348 |
- else if (verbose > 1) |
349 |
- printf("%s: %i byte%c\n", pathname, data_len, (data_len>1?'s':' ')); |
350 |
+ if (verbose == 0 + (xctx->extract ? 1 : 0)) |
351 |
+ printf("%.*s", pathname_len, pathname); |
352 |
+ else if (verbose == 1 + (xctx->extract ? 1 : 0)) |
353 |
+ printf("%.*s: %d byte%s\n", |
354 |
+ pathname_len, pathname, |
355 |
+ data_len, (data_len > 1 ? "s" : "")); |
356 |
+ else |
357 |
+ printf("%.*s: %d byte%s @ offset byte %d\n", |
358 |
+ pathname_len, pathname, |
359 |
+ data_len, (data_len > 1 ? "s" : ""), data_offset); |
360 |
+ |
361 |
+ if (!xctx->extract) |
362 |
+ return; |
363 |
|
364 |
if (!xpak_stdout) { |
365 |
- int fd = openat(dir_fd, pathname, |
366 |
- O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC, 0644); |
367 |
+ int fd = openat(xctx->dir_fd, pathname, |
368 |
+ O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, 0644); |
369 |
if (fd < 0) |
370 |
return; |
371 |
out = fdopen(fd, "w"); |
372 |
@@ -101,12 +108,14 @@ _xpak_extract_callback( |
373 |
int qxpak_main(int argc, char **argv) |
374 |
{ |
375 |
enum { XPAK_ACT_NONE, XPAK_ACT_LIST, XPAK_ACT_EXTRACT, XPAK_ACT_CREATE }; |
376 |
- int i, ret, dir_fd; |
377 |
+ int i, ret; |
378 |
char *xpak; |
379 |
char action = XPAK_ACT_NONE; |
380 |
+ struct qxpak_cb cbctx; |
381 |
|
382 |
- dir_fd = AT_FDCWD; |
383 |
xpak_stdout = 0; |
384 |
+ cbctx.dir_fd = AT_FDCWD; |
385 |
+ cbctx.extract = false; |
386 |
|
387 |
while ((i = GETOPT_LONG(QXPAK, qxpak, "")) != -1) { |
388 |
switch (i) { |
389 |
@@ -116,10 +125,10 @@ int qxpak_main(int argc, char **argv) |
390 |
case 'c': action = XPAK_ACT_CREATE; break; |
391 |
case 'O': xpak_stdout = 1; break; |
392 |
case 'd': |
393 |
- if (dir_fd != AT_FDCWD) |
394 |
+ if (cbctx.dir_fd != AT_FDCWD) |
395 |
err("Only use -d once"); |
396 |
- dir_fd = open(optarg, O_RDONLY|O_CLOEXEC|O_PATH); |
397 |
- if (dir_fd < 0) |
398 |
+ cbctx.dir_fd = open(optarg, O_RDONLY|O_CLOEXEC|O_PATH); |
399 |
+ if (cbctx.dir_fd < 0) |
400 |
errp("Could not open directory %s", optarg); |
401 |
break; |
402 |
} |
403 |
@@ -130,23 +139,32 @@ int qxpak_main(int argc, char **argv) |
404 |
xpak = argv[optind++]; |
405 |
argc -= optind; |
406 |
argv += optind; |
407 |
+ cbctx.argc = argc; |
408 |
+ cbctx.argv = argv; |
409 |
|
410 |
switch (action) { |
411 |
case XPAK_ACT_LIST: |
412 |
- ret = xpak_list(dir_fd, xpak, argc, argv, &_xpak_list_callback); |
413 |
+ ret = xpak_list(xpak, &cbctx, &_xpak_callback); |
414 |
break; |
415 |
case XPAK_ACT_EXTRACT: |
416 |
- ret = xpak_extract(dir_fd, xpak, argc, argv, &_xpak_extract_callback); |
417 |
+ cbctx.extract = true; |
418 |
+ ret = xpak_extract(xpak, &cbctx, &_xpak_callback); |
419 |
break; |
420 |
case XPAK_ACT_CREATE: |
421 |
- ret = xpak_create(dir_fd, xpak, argc, argv, 0, verbose); |
422 |
+ ret = xpak_create(cbctx.dir_fd, xpak, argc, argv, 0, verbose); |
423 |
break; |
424 |
default: |
425 |
ret = EXIT_FAILURE; |
426 |
} |
427 |
|
428 |
- if (dir_fd != AT_FDCWD) |
429 |
- close(dir_fd); |
430 |
+ if (cbctx.dir_fd != AT_FDCWD) |
431 |
+ close(cbctx.dir_fd); |
432 |
+ |
433 |
+ /* warn about non-matched args */ |
434 |
+ if (argc > 0 && (action == XPAK_ACT_LIST || action == XPAK_ACT_EXTRACT)) |
435 |
+ for (i = 0; i < argc; ++i) |
436 |
+ if (argv[i]) |
437 |
+ warn("Could not locate '%s' in archive", argv[i]); |
438 |
|
439 |
return ret; |
440 |
} |