From f217727c24c3cf1ec566a888ef409302377bb8d3 Mon Sep 17 00:00:00 2001 From: Patrick McDermott Date: Sat, 29 Apr 2023 18:55:16 -0400 Subject: opk: Extract control files --- diff --git a/configure.ac b/configure.ac index 38c62c2..fc76e4e 100644 --- a/configure.ac +++ b/configure.ac @@ -44,8 +44,9 @@ funcs_missing=false AC_CHECK_FUNCS( [\ fclose feof ferror fopen fprintf fputs fread free fwrite \ - localtime malloc memcmp memcpy memset printf puts snprintf \ - sprintf strcmp strcpy strftime strlen strncpy strtol + localtime malloc memcmp memcpy memset mkdir printf puts \ + snprintf sprintf stat strcmp strcpy strftime strlen strncpy \ + strtol ], [], [funcs_missing=true]) diff --git a/src/main.c b/src/main.c index 2c3fa87..08be875 100644 --- a/src/main.c +++ b/src/main.c @@ -36,10 +36,16 @@ extern const char *PACKAGE_VERSION_GIT; -const char *_optstring = "f:F:lLhV"; +const char *_optstring = "c:f:F:lLhV"; #ifdef HAVE_GETOPT_LONG struct option _longopts[] = { { + .name = "control-dir", + .has_arg = 1, + .flag = NULL, + .val = 'c', + }, + { .name = "control-file", .has_arg = 1, .flag = NULL, @@ -81,10 +87,11 @@ struct option _longopts[] = { static void _help(const char *program_name) { - printf(_("Usage: %s [-f CONTROL-FILE] [-F DATA-FILE] [-l] [-L] " - "PACKAGE\n"), program_name); + printf(_("Usage: %s [-c CONTROL-DIR] [-f CONTROL-FILE] [-F DATA-FILE] " + "[-l] [-L] PACKAGE\n"), program_name); #ifdef HAVE_GETOPT_LONG puts(_("Options:\n" +" -c, --control-dir=CONTROL-DIR Extract control files into CONTROL-DIR.\n" " -f, --control-file=CONTROL-FILE Print the contents of the named control " "file.\n" " If this option is given multiple times, the" @@ -210,6 +217,9 @@ main(int argc, char *argv[]) while ((opt = getopt(argc, argv, _optstring)) != -1) { #endif switch(opt) { + case 'c': + opkg_opk_opk_control_dir(opk, optarg); + break; case 'f': if (opt_l > 0) { _opt_mutex(program_name, 'f', 'l'); diff --git a/src/opk.c b/src/opk.c index db35cab..62b09f2 100644 --- a/src/opk.c +++ b/src/opk.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "defs.h" #include "gzip.h" @@ -41,6 +42,7 @@ struct opkg_opk_opk { struct _opkg_opk_opk_seek_name *print_data_tail; int list_control; int list_data; + const char *control_dir; FILE *file; char file_buffer[8192]; struct opkg_opk_gzip *outer_gzip; @@ -66,6 +68,7 @@ opkg_opk_opk_init(void) opk->print_data_tail = NULL; opk->list_control = 0; opk->list_data = 0; + opk->control_dir = NULL; opk->previously_printed = 0; return opk; @@ -128,6 +131,13 @@ opkg_opk_opk_list_data(struct opkg_opk_opk *opk) return OPKG_OPK_OK; } +int +opkg_opk_opk_control_dir(struct opkg_opk_opk *opk, const char *dir) +{ + opk->control_dir = dir; + return OPKG_OPK_OK; +} + static int _opkg_opk_opk_file_read(void *user_data, char **buffer, size_t *size) { @@ -213,58 +223,116 @@ _opkg_opk_opk_check_name(const char *member_name, static int _opkg_opk_opk_read_control(struct opkg_opk_opk *opk) { + struct stat stat_buf; + char *path; struct opkg_opk_ustar_member *member; int ret_list; + FILE *fp; + int print; int ret_read; char *buffer; size_t size; struct _opkg_opk_opk_seek_name *seek_name; - if (opk->list_control == 0 && opk->print_control_head == NULL) { + if (opk->control_dir != NULL) { + if (stat(opk->control_dir, &stat_buf) == 0) { + if (!S_ISDIR(stat_buf.st_mode)) { + fputs(_("Error: Cannot create control directory" + "\n"), stderr); + return OPKG_OPK_ERROR; + } + } else if (mkdir(opk->control_dir, 0755) != 0) { + fputs(_("Error: Cannot create control directory" + "\n"), stderr); + return OPKG_OPK_ERROR; + } + path = malloc(strlen(opk->control_dir) + + OPKG_OPK_USTAR_NAME_SIZE + 1); + if (path == NULL) { + return OPKG_OPK_ERROR; + } + } else if (opk->list_control == 0 && opk->print_control_head == NULL) { /* Not listing or printing any control files. */ return OPKG_OPK_OK; } if (_opkg_opk_opk_init_inner(opk) != OPKG_OPK_OK) { + if (opk->control_dir != NULL) { + free(path); + } return OPKG_OPK_ERROR; } while ((ret_list = opkg_opk_ustar_list(opk->inner_ustar, &member)) == OPKG_OPK_OK) { - if (opk->list_control > 0) { - buffer = member->name; - if (buffer[0] == '.' && buffer[1] == '/') { - buffer += 2; + /* Remove leading "./" if present and skip if nothing's left. */ + buffer = member->name; + if (buffer[0] == '.' && buffer[1] == '/') { + buffer += 2; + } + if (buffer[0] == '\0') { + free(member); + continue; + } + + /* Open file for extraction. */ + if (opk->control_dir != NULL) { + if (sprintf(path, "%s/%s", opk->control_dir, + member->name) <= 0) { + free(member); + _opkg_opk_opk_free_inner(opk); + free(path); + return OPKG_OPK_ERROR; } - if (buffer[0] != '\0') { - puts(buffer); - opk->previously_printed = 1; + fp = fopen(path, "wb"); + if (fp == NULL) { + fputs(_("Error: Failed to extract control file" + "\n"), stderr); + free(member); + _opkg_opk_opk_free_inner(opk); + free(path); + return OPKG_OPK_ERROR; } } - if (opk->print_control_head == NULL) { - free(member); - continue; + if (opk->list_control > 0) { + puts(buffer); + opk->previously_printed = 1; } - if (_opkg_opk_opk_check_name(member->name, + + if (opk->print_control_head != NULL && + _opkg_opk_opk_check_name(member->name, &opk->print_control_head, - &opk->print_control_tail) != + &opk->print_control_tail) == OPKG_OPK_OK) { - /* Name not requested for printing. */ - free(member); - continue; + /* Name requested for printing. */ + print = 1; + } else { + print = 0; } free(member); - if (opk->previously_printed == 1) { + if (print == 1 && opk->previously_printed == 1) { puts(""); } while ((ret_read = opkg_opk_ustar_read(opk->inner_ustar, &buffer, &size)) == OPKG_OPK_OK) { - if (fwrite(buffer, 1, size, stdout) != size) { + if (print == 1 && fwrite(buffer, 1, size, stdout) != + size) { fputs(_("Error: Failed to print control file\n") , stderr); _opkg_opk_opk_free_inner(opk); + if (opk->control_dir != NULL) { + free(path); + } + return OPKG_OPK_ERROR; + } + if (opk->control_dir != NULL && fwrite(buffer, 1, size, + fp) != size) { + fputs(_("Error: Failed to write control file\n") + , stderr); + _opkg_opk_opk_free_inner(opk); + free(path); return OPKG_OPK_ERROR; } } @@ -272,9 +340,25 @@ _opkg_opk_opk_read_control(struct opkg_opk_opk *opk) fputs(_("Error: Failed to read control file\n"), stderr); _opkg_opk_opk_free_inner(opk); + if (opk->control_dir != NULL) { + free(path); + } return OPKG_OPK_ERROR; } opk->previously_printed = 1; + + /* Close file for extraction. */ + if (opk->control_dir != NULL) { + if (fclose(fp) != 0) { + _opkg_opk_opk_free_inner(opk); + free(path); + return OPKG_OPK_ERROR; + } + } + } + if (opk->control_dir != NULL) { + /* Done with path buffer. */ + free(path); } if (ret_list == OPKG_OPK_ERROR) { fputs(_("Error: Failed to list control files\n"), stderr); @@ -337,6 +421,7 @@ _opkg_opk_opk_read_data(struct opkg_opk_opk *opk) size_max = 0; while ((ret = opkg_opk_ustar_list(opk->inner_ustar, &member)) == OPKG_OPK_OK) { + /* If listing, link members and update max column widths. */ if (opk->list_data > 0) { if (head == NULL) { head = member; diff --git a/src/opk.h b/src/opk.h index 4d70aa2..049953f 100644 --- a/src/opk.h +++ b/src/opk.h @@ -80,6 +80,18 @@ int opkg_opk_opk_list_data(struct opkg_opk_opk *opk); /* + * Sets the directory into which to extract control files. The directory (but + * not its ancestors) will be created if it doesn't exist. + * Parameters: + * - opk: Package structure. + * - dir: Directory. + * Returns: + * - OPKG_OPK_OK. + */ +int +opkg_opk_opk_control_dir(struct opkg_opk_opk *opk, const char *dir); + +/* * Performs the configured read actions. * Parameters: * - file_name: Package's file name. -- cgit v0.9.1