From dc25a788d874d9ee95738b9fa56d2a06f6a31141 Mon Sep 17 00:00:00 2001 From: Patrick McDermott Date: Sun, 30 Apr 2023 03:44:20 -0400 Subject: opk/write: Build mode (WIP) --- diff --git a/src/main.c b/src/main.c index 08be875..4a672b2 100644 --- a/src/main.c +++ b/src/main.c @@ -36,16 +36,28 @@ extern const char *PACKAGE_VERSION_GIT; -const char *_optstring = "c:f:F:lLhV"; +const char *_optstring = "bc:d:f:F:lLhV"; #ifdef HAVE_GETOPT_LONG struct option _longopts[] = { { + .name = "build", + .has_arg = 0, + .flag = NULL, + .val = 'b', + }, + { .name = "control-dir", .has_arg = 1, .flag = NULL, .val = 'c', }, { + .name = "data-dir", + .has_arg = 1, + .flag = NULL, + .val = 'd', + }, + { .name = "control-file", .has_arg = 1, .flag = NULL, @@ -89,9 +101,17 @@ _help(const char *program_name) { printf(_("Usage: %s [-c CONTROL-DIR] [-f CONTROL-FILE] [-F DATA-FILE] " "[-l] [-L] PACKAGE\n"), program_name); + printf(_(" or: %s -b -c CONTROL-DIR -d DATA-DIR PACKAGE\n"), + program_name); #ifdef HAVE_GETOPT_LONG puts(_("Options:\n" -" -c, --control-dir=CONTROL-DIR Extract control files into CONTROL-DIR.\n" +" -b, --build Create a package from the specified\n" +" CONTROL-DIR and DATA-DIR.\n" +" -c, --control-dir=CONTROL-DIR In build mode, read control files from\n" +" CONTROL-DIR. Otherwise, extract control\n" +" files into CONTROL-DIR.\n" +" -d, --data-dir=DATA-DIR In build mode, read data files from " + "DATA-DIR\n" " -f, --control-file=CONTROL-FILE Print the contents of the named control " "file.\n" " If this option is given multiple times, the" @@ -121,6 +141,11 @@ _help(const char *program_name) " -V, --version Show version information and exit.")); #else puts(_("Options:\n" +" -b Create a package from the specified CONTROL-DIR and DATA-DIR.\n" +" -c In build mode, read control files from CONTROL-DIR. Otherwise, extract" + "\n" +" control files into CONTROL-DIR.\n" +" -d In build mode, read data files from DATA-DIR\n" " -f Print the contents of the named control file. If this option is given\n" " multiple times, the named control files will be printed in the order " "they\n" @@ -182,6 +207,7 @@ main(int argc, char *argv[]) { const char *program_name; struct opkg_opk_opk *opk; + int build; int opt_f; int opt_F; int opt_l; @@ -206,6 +232,7 @@ main(int argc, char *argv[]) } opterr = 0; + build = 0; opt_f = 0; opt_F = 0; opt_l = 0; @@ -217,9 +244,15 @@ main(int argc, char *argv[]) while ((opt = getopt(argc, argv, _optstring)) != -1) { #endif switch(opt) { + case 'b': + build = 1; + break; case 'c': opkg_opk_opk_control_dir(opk, optarg); break; + case 'd': + opkg_opk_opk_data_dir(opk, optarg); + break; case 'f': if (opt_l > 0) { _opt_mutex(program_name, 'f', 'l'); @@ -298,10 +331,17 @@ main(int argc, char *argv[]) return EXIT_FAILURE; } - /* Read package. */ - if (opkg_opk_opk_read(opk, argv[0]) != OPKG_OPK_OK) { - opkg_opk_opk_free(opk); - return EXIT_FAILURE; + /* Read or build package. */ + if (build == 1) { + if (opkg_opk_opk_write(opk, argv[0]) != OPKG_OPK_OK) { + opkg_opk_opk_free(opk); + return EXIT_FAILURE; + } + } else { + if (opkg_opk_opk_read(opk, argv[0]) != OPKG_OPK_OK) { + opkg_opk_opk_free(opk); + return EXIT_FAILURE; + } } opkg_opk_opk_free(opk); diff --git a/src/opk.c b/src/opk.c index 4dbefcf..5619bc5 100644 --- a/src/opk.c +++ b/src/opk.c @@ -110,6 +110,13 @@ opkg_opk_opk_control_dir(struct opkg_opk_opk *opk, const char *dir) return OPKG_OPK_OK; } +int +opkg_opk_opk_data_dir(struct opkg_opk_opk *opk, const char *dir) +{ + opk->data_dir = dir; + return OPKG_OPK_OK; +} + void opkg_opk_opk_free(struct opkg_opk_opk *opk) { diff --git a/src/opk.h b/src/opk.h index 049953f..8148dc8 100644 --- a/src/opk.h +++ b/src/opk.h @@ -80,8 +80,9 @@ 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. + * Sets the directory into which to extract control files when reading or in + * which to find control files when writing. When extracting, the directory + * (but not its ancestors) will be created if it doesn't exist. * Parameters: * - opk: Package structure. * - dir: Directory. @@ -92,6 +93,17 @@ int opkg_opk_opk_control_dir(struct opkg_opk_opk *opk, const char *dir); /* + * Sets the directory in which to find data files when writing. + * Parameters: + * - opk: Package structure. + * - dir: Directory. + * Returns: + * - OPKG_OPK_OK. + */ +int +opkg_opk_opk_data_dir(struct opkg_opk_opk *opk, const char *dir); + +/* * Performs the configured read actions. * Parameters: * - file_name: Package's file name. @@ -100,6 +112,14 @@ int opkg_opk_opk_read(struct opkg_opk_opk *opk, const char *file_name); /* + * Performs the configured write actions. + * Parameters: + * - file_name: Package's file name. + */ +int +opkg_opk_opk_write(struct opkg_opk_opk *opk, const char *file_name); + +/* * Frees a package structure. * Parameters: * - opk: Package structure. diff --git a/src/opk/local.mk b/src/opk/local.mk index a535a4f..a4722ba 100644 --- a/src/opk/local.mk +++ b/src/opk/local.mk @@ -1,3 +1,4 @@ opkg_opk_SOURCES += \ %reldir%/opk.h \ - %reldir%/read.c + %reldir%/read.c \ + %reldir%/write.c diff --git a/src/opk/opk.h b/src/opk/opk.h index e5fc4d2..afd39b6 100644 --- a/src/opk/opk.h +++ b/src/opk/opk.h @@ -39,6 +39,7 @@ struct opkg_opk_opk { int list_control; int list_data; const char *control_dir; + const char *data_dir; FILE *file; char file_buffer[8192]; struct opkg_opk_gzip *outer_gzip; diff --git a/src/opk/write.c b/src/opk/write.c new file mode 100644 index 0000000..12a36c6 --- /dev/null +++ b/src/opk/write.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2023 Patrick McDermott + * + * This file is part of opkg-opkg. + * + * opkg-opkg is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opkg-opkg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opkg-opkg. If not, see . + */ + +#include +#include +#include +#include +#include "../defs.h" +#include "../dirent.h" +#include "../gzip.h" +#include "../i18n.h" +#include "../opk.h" +#include "../ustar.h" +#include "opk.h" + +static int +_opkg_opk_opk_write_file(void *user_data, size_t size) +{ + struct opkg_opk_opk *opk = user_data; + + if (fwrite(opk->file_buffer, 1, sizeof(opk->file_buffer), opk->file) == + size) { + return OPKG_OPK_OK; + } else { + return OPKG_OPK_ERROR; + } +} + +int +opkg_opk_opk_write(struct opkg_opk_opk *opk, const char *file_name) +{ + int ret; + struct opkg_opk_dirent dirent; + char *buffer; + size_t size; + + ret = OPKG_OPK_OK; + + /* Open outer archive. */ + opk->file = fopen(file_name, "wb"); + if (opk->file == NULL) { + fprintf(stderr, _("Error: Failed to open file \"%s\"\n"), + file_name); + ret = OPKG_OPK_ERROR; + goto out0; + } + + /* Initialize outer gzip decompressor. */ + opk->outer_gzip = opkg_opk_gzip_init_write(&_opkg_opk_opk_write_file, + opk); + if (opk->outer_gzip == NULL) { + fputs(_("Error: Failed to initialize\n"), stderr); + ret = OPKG_OPK_ERROR; + goto out1; + } + opkg_opk_gzip_set_write_buffer(opk->outer_gzip, opk->file_buffer, + sizeof(opk->file_buffer)); + + /* Initialize outer ustar unarchiver. */ + opk->outer_ustar = opkg_opk_ustar_init(opk->outer_gzip); + if (opk->outer_ustar == NULL) { + fputs(_("Error: Failed to initialize\n"), stderr); + ret = OPKG_OPK_ERROR; + goto out2; + } + + /* Write version file. */ + dirent.name = "debian-binary"; + dirent.parent = NULL; + if (opkg_opk_ustar_write_header(opk->outer_ustar, &dirent, 0644, + 0, getpwuid(0)->pw_name, + 0, getgrgid(0)->gr_name, + 4, '-', NULL) != OPKG_OPK_OK) { + fputs(_("Error: Failed to write header\n"), stderr); + ret = OPKG_OPK_ERROR; + goto out3; + } + opkg_opk_ustar_get_buffer(opk->outer_ustar, &buffer, &size); + memcpy(buffer, "2.0\n", 4); + if (opkg_opk_ustar_write_data(opk->outer_ustar, 4) != OPKG_OPK_OK) { + fputs(_("Error: Failed to write data\n"), stderr); + ret = OPKG_OPK_ERROR; + goto out3; + } + + /* TODO: control.tar.gz and data.tar.gz */ + + /* Write trailer. */ + if (opkg_opk_ustar_write_trailer(opk->outer_ustar) != OPKG_OPK_OK) { + fputs(_("Error: Failed to write trailer\n"), stderr); + ret = OPKG_OPK_ERROR; + goto out3; + } + + out3: + opkg_opk_ustar_free(opk->outer_ustar); + out2: + opkg_opk_gzip_free(opk->outer_gzip); + out1: + fclose(opk->file); + out0: + return ret; +} -- cgit v0.9.1