commit: 5ec1f4368412c8d6f02148d3d9cb109050c8c626
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Fri Nov 15 13:50:10 2019 +0000
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Fri Nov 15 13:50:10 2019 +0000
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=5ec1f436
libq/xpak: rework to reuse more code
- introduce xpak_process{,_fd} to replace the very similar list and extract
- add _fd variant to be able to pass already open filedescriptor
- rework interface to carry a context pointer for the callback func for
more flexibility
- adapt qxpak for the interface changes
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
libq/xpak.c | 132 ++++++++++++++++++++++++++----------------------------------
libq/xpak.h | 26 +++---------
qxpak.c | 98 ++++++++++++++++++++++++++------------------
3 files changed, 120 insertions(+), 136 deletions(-)
diff --git a/libq/xpak.c b/libq/xpak.c
index c2e93f9..9692eab 100644
--- a/libq/xpak.c
+++ b/libq/xpak.c
@@ -39,23 +39,22 @@
#define XPAK_END_MSG_LEN 8
typedef struct {
- int dir_fd;
+ void *ctx;
FILE *fp;
- int index_len;
- int data_len;
+ unsigned int index_len;
+ unsigned int data_len;
char *index, *data;
} _xpak_archive;
-typedef void (*xpak_callback_t)(int,char*,int,int,int,char*);
-
static void _xpak_walk_index(
_xpak_archive *x,
- int argc,
- char **argv,
xpak_callback_t func)
{
- int i, pathname_len, data_offset, data_len;
- char *p, pathname[100];
+ unsigned int pathname_len;
+ unsigned int data_offset;
+ unsigned int data_len;
+ char *p;
+ char pathname[100];
p = x->index;
while ((p - x->index) < x->index_len) {
@@ -73,43 +72,26 @@ static void _xpak_walk_index(
p += 4;
data_len = READ_BE_INT32((unsigned char*)p);
p += 4;
- if (argc) {
- for (i = 0; i < argc; ++i) {
- if (argv[i] && !strcmp(pathname, argv[i])) {
- argv[i] = NULL;
- break;
- }
- }
- if (i == argc)
- continue;
- }
- (*func)(x->dir_fd, pathname, pathname_len,
+ (*func)(x->ctx, pathname, pathname_len,
data_offset, data_len, x->data);
}
-
- if (argc)
- for (i = 0; i < argc; ++i)
- if (argv[i])
- warn("Could not locate '%s' in archive",
argv[i]);
}
-static _xpak_archive *_xpak_open(const char *file)
+static _xpak_archive *_xpak_open(const int fd)
{
static _xpak_archive ret;
char buf[XPAK_START_LEN];
/* init the file */
memset(&ret, 0x00, sizeof(ret));
- if (file[0] == '-' && file[1] == '\0')
- ret.fp = stdin;
- else if ((ret.fp = fopen(file, "r")) == NULL)
+ if ((ret.fp = fdopen(fd, "r")) == NULL)
return NULL;
/* verify this xpak doesnt suck */
if (fread(buf, 1, XPAK_START_LEN, ret.fp) != XPAK_START_LEN)
goto close_and_ret;
if (memcmp(buf, XPAK_START_MSG, XPAK_START_MSG_LEN)) {
- warn("%s: Invalid xpak", file);
+ warn("Not an xpak file");
goto close_and_ret;
}
@@ -117,7 +99,7 @@ static _xpak_archive *_xpak_open(const char *file)
ret.index_len = READ_BE_INT32((unsigned char*)buf+XPAK_START_MSG_LEN);
ret.data_len = READ_BE_INT32((unsigned char*)buf+XPAK_START_MSG_LEN+4);
if (!ret.index_len || !ret.data_len) {
- warn("Skipping empty archive '%s'", file);
+ warn("Skipping empty archive");
goto close_and_ret;
}
@@ -135,52 +117,21 @@ static void _xpak_close(_xpak_archive *x)
}
int
-xpak_list(
- int dir_fd,
- const char *file,
- int argc,
- char **argv,
- xpak_callback_t func)
-{
- _xpak_archive *x;
- char buf[BUFSIZE];
- size_t ret;
-
- x = _xpak_open(file);
- if (!x)
- return 1;
-
- x->dir_fd = dir_fd;
- x->index = buf;
- if (x->index_len >= sizeof(buf))
- err("index length %d exceeds limit %zd", x->index_len,
sizeof(buf));
- ret = fread(x->index, 1, x->index_len, x->fp);
- if (ret != (size_t)x->index_len)
- err("insufficient data read, got %zd, requested %d", ret,
x->index_len);
- _xpak_walk_index(x, argc, argv, func);
-
- _xpak_close(x);
-
- return 0;
-}
-
-int
-xpak_extract(
- int dir_fd,
- const char *file,
- int argc,
- char **argv,
+xpak_process_fd(
+ int fd,
+ bool get_data,
+ void *ctx,
xpak_callback_t func)
{
_xpak_archive *x;
char buf[BUFSIZE], ext[BUFSIZE*32];
size_t in;
- x = _xpak_open(file);
+ x = _xpak_open(fd);
if (!x)
return 1;
- x->dir_fd = dir_fd;
+ x->ctx = ctx;
x->index = buf;
if (x->index_len >= sizeof(buf))
@@ -189,22 +140,51 @@ xpak_extract(
if (in != (size_t)x->index_len)
err("insufficient data read, got %zd, requested %d", in,
x->index_len);
- /* the xpak may be large (like when it has CONTENTS) #300744 */
- x->data = (size_t)x->data_len < sizeof(ext) ? ext :
xmalloc(x->data_len);
- in = fread(x->data, 1, x->data_len, x->fp);
- if (in != (size_t)x->data_len)
- err("insufficient data read, got %zd, requested %d", in,
x->data_len);
+ if (get_data) {
+ /* the xpak may be large (like when it has CONTENTS) #300744 */
+ x->data = (size_t)x->data_len < sizeof(ext) ?
+ ext : xmalloc(x->data_len);
+ in = fread(x->data, 1, x->data_len, x->fp);
+ if (in != (size_t)x->data_len)
+ err("insufficient data read, got %zd, requested %d",
+ in, x->data_len);
+ } else {
+ x->data = NULL;
+ x->data_len = 0;
+ }
- _xpak_walk_index(x, argc, argv, func);
+ _xpak_walk_index(x, func);
_xpak_close(x);
- if (x->data != ext)
+ if (get_data && x->data != ext)
free(x->data);
return 0;
}
+int
+xpak_process(
+ const char *file,
+ bool get_data,
+ void *ctx,
+ xpak_callback_t func)
+{
+ int fd = -1;
+ int ret;
+
+ if (file[0] == '-' && file[1] == '\0')
+ fd = 0;
+ else if ((fd = open(file, O_RDONLY | O_CLOEXEC)) == -1)
+ return -1;
+
+ ret = xpak_process_fd(fd, get_data, ctx, func);
+ if (ret != 0)
+ warn("Unable to open file '%s'", file);
+
+ return ret;
+}
+
static void
_xpak_add_file(
int dir_fd,
@@ -279,7 +259,7 @@ xpak_create(
const char *file,
int argc,
char **argv,
- char append,
+ bool append,
int verbose)
{
FILE *findex, *fdata, *fout;
diff --git a/libq/xpak.h b/libq/xpak.h
index 0b318b2..aeafdae 100644
--- a/libq/xpak.h
+++ b/libq/xpak.h
@@ -6,26 +6,12 @@
#ifndef _XPAK_H
#define _XPAK_H 1
-typedef void (*xpak_callback_t)(int,char*,int,int,int,char*);
+typedef void (*xpak_callback_t)(void *, char *, int, int, int, char *);
-int xpak_list(
- int dir_fd,
- const char *file,
- int argc,
- char **argv,
- xpak_callback_t func);
-int xpak_extract(
- int dir_fd,
- const char *file,
- int argc,
- char **argv,
- xpak_callback_t func);
-int xpak_create(
- int dir_fd,
- const char *file,
- int argc,
- char **argv,
- char append,
- int v);
+int xpak_process_fd(int, bool, void *, xpak_callback_t);
+int xpak_process(const char *, bool, void *, xpak_callback_t);
+#define xpak_list(A,B,C) xpak_process(A,false,B,C)
+#define xpak_extract(A,B,C) xpak_process(A,true,B,C)
+int xpak_create(int, const char *, int, char **, bool, int);
#endif
diff --git a/qxpak.c b/qxpak.c
index eb19cae..fd0ec5d 100644
--- a/qxpak.c
+++ b/qxpak.c
@@ -42,31 +42,16 @@ static const char * const qxpak_opts_help[] = {
static char xpak_stdout;
-static void
-_xpak_list_callback(
- int dir_fd,
- char *pathname,
- int pathname_len,
- int data_offset,
- int data_len,
- char *data)
-{
- (void)dir_fd;
- (void)pathname_len;
- (void)data;
-
- if (!verbose)
- puts(pathname);
- else if (verbose == 1)
- printf("%s: %i byte%c\n", pathname, data_len, (data_len>1?'s':'
'));
- else
- printf("%s: %i byte%c @ offset byte %i\n",
- pathname, data_len, (data_len>1?'s':' '), data_offset);
-}
+struct qxpak_cb {
+ int dir_fd;
+ int argc;
+ char **argv;
+ bool extract;
+};
static void
-_xpak_extract_callback(
- int dir_fd,
+_xpak_callback(
+ void *ctx,
char *pathname,
int pathname_len,
int data_offset,
@@ -74,16 +59,38 @@ _xpak_extract_callback(
char *data)
{
FILE *out;
- (void)pathname_len;
+ struct qxpak_cb *xctx = (struct qxpak_cb *)ctx;
+
+ /* see if there is a match when there is a selection */
+ if (xctx->argc > 0) {
+ int i;
+ for (i = 0; i < xctx->argc; i++) {
+ if (xctx->argv[i] && !strcmp(pathname, xctx->argv[i])) {
+ xctx->argv[i] = NULL;
+ break;
+ }
+ }
+ if (i == xctx->argc)
+ return;
+ }
- if (verbose == 1)
- puts(pathname);
- else if (verbose > 1)
- printf("%s: %i byte%c\n", pathname, data_len, (data_len>1?'s':'
'));
+ if (verbose == 0 + (xctx->extract ? 1 : 0))
+ printf("%.*s", pathname_len, pathname);
+ else if (verbose == 1 + (xctx->extract ? 1 : 0))
+ printf("%.*s: %d byte%s\n",
+ pathname_len, pathname,
+ data_len, (data_len > 1 ? "s" : ""));
+ else
+ printf("%.*s: %d byte%s @ offset byte %d\n",
+ pathname_len, pathname,
+ data_len, (data_len > 1 ? "s" : ""),
data_offset);
+
+ if (!xctx->extract)
+ return;
if (!xpak_stdout) {
- int fd = openat(dir_fd, pathname,
- O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC, 0644);
+ int fd = openat(xctx->dir_fd, pathname,
+ O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, 0644);
if (fd < 0)
return;
out = fdopen(fd, "w");
@@ -101,12 +108,14 @@ _xpak_extract_callback(
int qxpak_main(int argc, char **argv)
{
enum { XPAK_ACT_NONE, XPAK_ACT_LIST, XPAK_ACT_EXTRACT, XPAK_ACT_CREATE
};
- int i, ret, dir_fd;
+ int i, ret;
char *xpak;
char action = XPAK_ACT_NONE;
+ struct qxpak_cb cbctx;
- dir_fd = AT_FDCWD;
xpak_stdout = 0;
+ cbctx.dir_fd = AT_FDCWD;
+ cbctx.extract = false;
while ((i = GETOPT_LONG(QXPAK, qxpak, "")) != -1) {
switch (i) {
@@ -116,10 +125,10 @@ int qxpak_main(int argc, char **argv)
case 'c': action = XPAK_ACT_CREATE; break;
case 'O': xpak_stdout = 1; break;
case 'd':
- if (dir_fd != AT_FDCWD)
+ if (cbctx.dir_fd != AT_FDCWD)
err("Only use -d once");
- dir_fd = open(optarg, O_RDONLY|O_CLOEXEC|O_PATH);
- if (dir_fd < 0)
+ cbctx.dir_fd = open(optarg, O_RDONLY|O_CLOEXEC|O_PATH);
+ if (cbctx.dir_fd < 0)
errp("Could not open directory %s", optarg);
break;
}
@@ -130,23 +139,32 @@ int qxpak_main(int argc, char **argv)
xpak = argv[optind++];
argc -= optind;
argv += optind;
+ cbctx.argc = argc;
+ cbctx.argv = argv;
switch (action) {
case XPAK_ACT_LIST:
- ret = xpak_list(dir_fd, xpak, argc, argv, &_xpak_list_callback);
+ ret = xpak_list(xpak, &cbctx, &_xpak_callback);
break;
case XPAK_ACT_EXTRACT:
- ret = xpak_extract(dir_fd, xpak, argc, argv,
&_xpak_extract_callback);
+ cbctx.extract = true;
+ ret = xpak_extract(xpak, &cbctx, &_xpak_callback);
break;
case XPAK_ACT_CREATE:
- ret = xpak_create(dir_fd, xpak, argc, argv, 0, verbose);
+ ret = xpak_create(cbctx.dir_fd, xpak, argc, argv, 0, verbose);
break;
default:
ret = EXIT_FAILURE;
}
- if (dir_fd != AT_FDCWD)
- close(dir_fd);
+ if (cbctx.dir_fd != AT_FDCWD)
+ close(cbctx.dir_fd);
+
+ /* warn about non-matched args */
+ if (argc > 0 && (action == XPAK_ACT_LIST || action == XPAK_ACT_EXTRACT))
+ for (i = 0; i < argc; ++i)
+ if (argv[i])
+ warn("Could not locate '%s' in archive",
argv[i]);
return ret;
}