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;
 }

Reply via email to