summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McDermott <patrick.mcdermott@libiquity.com>2023-04-29 18:55:16 (EDT)
committer Patrick McDermott <patrick.mcdermott@libiquity.com>2023-04-29 18:55:16 (EDT)
commitf217727c24c3cf1ec566a888ef409302377bb8d3 (patch)
tree4a168285572a278b819df783b778aad6d43792f7
parent6c956aef8ec09be9fafaec495145b5f64df678b9 (diff)
opk: Extract control files
-rw-r--r--configure.ac5
-rw-r--r--src/main.c16
-rw-r--r--src/opk.c121
-rw-r--r--src/opk.h12
4 files changed, 131 insertions, 23 deletions
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include <time.h>
#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.