diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.gitignore | 1 | ||||
-rw-r--r-- | src/defs.h | 27 | ||||
-rw-r--r-- | src/dirent.c | 114 | ||||
-rw-r--r-- | src/dirent.h | 33 | ||||
-rw-r--r-- | src/gzip.c | 263 | ||||
-rw-r--r-- | src/gzip.h | 82 | ||||
-rw-r--r-- | src/i18n.h | 11 | ||||
-rw-r--r-- | src/local.mk | 16 | ||||
-rw-r--r-- | src/main.c | 370 | ||||
-rw-r--r-- | src/opk.c | 151 | ||||
-rw-r--r-- | src/opk.h | 144 | ||||
-rw-r--r-- | src/opk/local.mk | 4 | ||||
-rw-r--r-- | src/opk/opk.h | 62 | ||||
-rw-r--r-- | src/opk/read.c | 669 | ||||
-rw-r--r-- | src/opk/write.c | 551 | ||||
-rw-r--r-- | src/specials.c | 131 | ||||
-rw-r--r-- | src/specials.h | 38 | ||||
-rw-r--r-- | src/ustar.c | 446 | ||||
-rw-r--r-- | src/ustar.h | 117 |
19 files changed, 0 insertions, 3230 deletions
diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index e0f5f90..0000000 --- a/src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/opkg-opk diff --git a/src/defs.h b/src/defs.h deleted file mode 100644 index 24e9776..0000000 --- a/src/defs.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#ifndef OPKG_OPK_DEFS_H_ -#define OPKG_OPK_DEFS_H_ - -#define OPKG_OPK_OK 0 -#define OPKG_OPK_END 1 -#define OPKG_OPK_ERROR -1 - -#endif /* OPKG_OPK_DEFS_H_ */ diff --git a/src/dirent.c b/src/dirent.c deleted file mode 100644 index 575e834..0000000 --- a/src/dirent.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "defs.h" -#include "dirent.h" - -static int -_opkg_opk_dirent_name_prefix(struct opkg_opk_dirent *dirent, int is_dir, - char **name_buf, size_t *name_buf_len, - char **pref_buf, size_t *pref_buf_len, - size_t *name_len, size_t *pref_len) -{ - size_t len; - char **buf; - int sep; - - len = strlen(dirent->name); - if ((*name_len > 0 || is_dir) && *name_len + len + 1 <= *name_buf_len) { - /* Space available in name buffer. Not last node, or is a - * directory, so append separator. */ - buf = name_buf; - *name_len += len + 1; - sep = 1; - } else if (*name_len == 0 && *name_len + len <= *name_buf_len) { - /* Space available in name buffer. Last node (first in - * recursion), so don't append separator. */ - buf = name_buf; - *name_len += len; - sep = 0; - } else if (*pref_len > 0 && *pref_len + len + 1 <= *pref_buf_len) { - /* Space available in prefix buffer. Not last node, so append - * separator. */ - buf = pref_buf; - *pref_len += len + 1; - sep = 1; - } else if (*pref_len == 0 && *pref_len + len <= *pref_buf_len) { - /* Space available in prefix buffer. Last node (first in - * recursion), so don't append separator. */ - buf = pref_buf; - *pref_len += len; - sep = 0; - } else { - /* Both buffers full. */ - return OPKG_OPK_ERROR; - } - if (*buf == NULL) { - /* Caller provided a NULL buffer pointer. */ - return OPKG_OPK_ERROR; - } - - /* Recurse. */ - if (dirent->parent != NULL && - _opkg_opk_dirent_name_prefix(dirent->parent, is_dir, - name_buf, name_buf_len, pref_buf, pref_buf_len, - name_len, pref_len) == OPKG_OPK_ERROR) { - return OPKG_OPK_ERROR; - } - - /* Copy node name and possibly separator suffix. */ - memcpy(*buf, dirent->name, len); - *buf += len; - if (sep == 1) { - **buf = '/'; - *buf += 1; - } - - return OPKG_OPK_OK; -} - -int -opkg_opk_dirent_name_prefix(struct opkg_opk_dirent *dirent, int is_dir, - char *name_buf, size_t name_buf_len, - char *pref_buf, size_t pref_buf_len) -{ - size_t name_len = 0; - size_t pref_len = 0; - char *name = name_buf; - char *pref = pref_buf; - - /* NUL bytes */ - --name_buf_len; - --pref_buf_len; - - if (_opkg_opk_dirent_name_prefix(dirent, is_dir, - &name_buf, &name_buf_len, - &pref_buf, &pref_buf_len, - &name_len, &pref_len) == OPKG_OPK_ERROR) { - return OPKG_OPK_ERROR; - } - - name[name_len] = '\0'; - pref[pref_len] = '\0'; - - return OPKG_OPK_OK; -} diff --git a/src/dirent.h b/src/dirent.h deleted file mode 100644 index 959ca1b..0000000 --- a/src/dirent.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#ifndef OPKG_OPK_DIRENT_H_ -#define OPKG_OPK_DIRENT_H_ - -struct opkg_opk_dirent { - const char *name; - struct opkg_opk_dirent *parent; -}; - -int -opkg_opk_dirent_name_prefix(struct opkg_opk_dirent *dirent, int is_dir, - char *name_buf, size_t name_buf_len, - char *pref_buf, size_t pref_buf_len); - -#endif /* OPKG_OPK_DIRENT_H_ */ diff --git a/src/gzip.c b/src/gzip.c deleted file mode 100644 index 819a4e9..0000000 --- a/src/gzip.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <zlib.h> -#include "defs.h" -#include "gzip.h" -#include "ustar.h" - -#define OPKG_OPK_GZIP_WINDOW_BITS_ (15 + 16) - -enum _opkg_opk_gzip_dir { - _OPKG_OPK_GZIP_DIR_READ, - _OPKG_OPK_GZIP_DIR_WRITE, -}; - -struct opkg_opk_gzip { - enum _opkg_opk_gzip_dir dir; - opkg_opk_gzip_read_func *read_func; - void *user_data; - FILE *write_fp; - char write_buffer[512]; - size_t written; - z_stream stream; - gz_header gz_header; -}; - -struct opkg_opk_gzip * -opkg_opk_gzip_init_read(opkg_opk_gzip_read_func *read_func, void *user_data) -{ - struct opkg_opk_gzip *gzip; - - gzip = malloc(sizeof(*gzip)); - if (gzip == NULL) { - return NULL; - } - - gzip->dir = _OPKG_OPK_GZIP_DIR_READ; - gzip->read_func = read_func; - gzip->user_data = user_data; - - gzip->stream.zalloc = Z_NULL; - gzip->stream.zfree = Z_NULL; - gzip->stream.opaque = Z_NULL; - - gzip->stream.next_in = Z_NULL; - gzip->stream.avail_in = 0; - if (inflateInit2(&gzip->stream, OPKG_OPK_GZIP_WINDOW_BITS_) != Z_OK) { - free(gzip); - return NULL; - } - - return gzip; -} - -struct opkg_opk_gzip * -opkg_opk_gzip_init_write(FILE *write_fp) -{ - struct opkg_opk_gzip *gzip; - - gzip = malloc(sizeof(*gzip)); - if (gzip == NULL) { - return NULL; - } - - gzip->dir = _OPKG_OPK_GZIP_DIR_WRITE; - gzip->write_fp = write_fp; - gzip->written = 0; - - gzip->stream.zalloc = Z_NULL; - gzip->stream.zfree = Z_NULL; - gzip->stream.opaque = Z_NULL; - - gzip->stream.next_out = Z_NULL; - gzip->stream.avail_out = 0; - if (deflateInit2(&gzip->stream, 9, Z_DEFLATED, - OPKG_OPK_GZIP_WINDOW_BITS_, 9, - Z_DEFAULT_STRATEGY) != Z_OK) { - free(gzip); - return NULL; - } - gzip->gz_header.text = 0; - gzip->gz_header.time = 0; /* Stored as 32-bit uint */ - gzip->gz_header.os = 3; /* Unix, per RFC 1952 */ - gzip->gz_header.extra = Z_NULL; - gzip->gz_header.name = Z_NULL; - gzip->gz_header.comment = Z_NULL; - gzip->gz_header.hcrc = 0; - if (deflateSetHeader(&gzip->stream, &gzip->gz_header) != Z_OK) { - deflateEnd(&gzip->stream); - free(gzip); - return NULL; - } - - return gzip; -} - -int -opkg_opk_gzip_read(struct opkg_opk_gzip *gzip, void *record) -{ - int end; - - /* Sanity check */ - if (gzip->dir != _OPKG_OPK_GZIP_DIR_READ) { - return OPKG_OPK_ERROR; - } - - gzip->stream.next_out = record; - gzip->stream.avail_out = OPKG_OPK_USTAR_RECORD_SIZE; - - for (;;) { - end = 0; - if (gzip->stream.avail_in == 0) { - /* Input buffer is empty and needs refilled. */ - switch (gzip->read_func(gzip->user_data, - (char **) &gzip->stream.next_in, - (size_t *) &gzip->stream. - avail_in)) { - case OPKG_OPK_OK: - break; - case OPKG_OPK_END: - end = 1; - break; - case OPKG_OPK_ERROR: - default: - return OPKG_OPK_ERROR; - } - } - switch (inflate(&gzip->stream, Z_SYNC_FLUSH)) { - case Z_OK: - break; - case Z_BUF_ERROR: - if (end == 1) { - return OPKG_OPK_ERROR; - } - break; - case Z_STREAM_END: - if (gzip->stream.avail_out != 0) { - /* Premature end */ - return OPKG_OPK_ERROR; - } - return OPKG_OPK_END; - default: - return OPKG_OPK_ERROR; - } - if (gzip->stream.avail_out == 0) { - /* Output buffer is filled and ready for use. */ - return OPKG_OPK_OK; - } - } -} - -static int -_opkg_opk_gzip_write(struct opkg_opk_gzip *gzip, void *record, size_t size, - int last) -{ - size_t len; - - /* Sanity check */ - if (gzip->dir != _OPKG_OPK_GZIP_DIR_WRITE) { - return OPKG_OPK_ERROR; - } - - gzip->stream.next_in = record; - gzip->stream.avail_in = size; - - do { - gzip->stream.next_out = gzip->write_buffer; - gzip->stream.avail_out = sizeof(gzip->write_buffer); - switch (deflate(&gzip->stream, - (last > 0 ? Z_FINISH : Z_NO_FLUSH))) { - case Z_OK: - case Z_BUF_ERROR: - case Z_STREAM_END: - break; - default: - return OPKG_OPK_ERROR; - } - /* Process output buffer. */ - len = sizeof(gzip->write_buffer) - gzip->stream.avail_out; - if (fwrite(gzip->write_buffer, 1, len, gzip->write_fp) != len) { - return OPKG_OPK_ERROR; - } - gzip->written += len; - } while (gzip->stream.avail_out == 0); - - if (gzip->stream.avail_in != 0) { - return OPKG_OPK_ERROR; - } - if (last == 0) { - /* Input buffer is empty and needs refilled. */ - return OPKG_OPK_OK; - } else { - return OPKG_OPK_END; - } -} - -int -opkg_opk_gzip_write(struct opkg_opk_gzip *gzip, void *record, size_t size) -{ - if (_opkg_opk_gzip_write(gzip, record, size, 0) == OPKG_OPK_OK) { - return OPKG_OPK_OK; - } else { - return OPKG_OPK_ERROR; - } -} - -size_t -opkg_opk_gzip_written(struct opkg_opk_gzip *gzip) -{ - return gzip->written; -} - -int -opkg_opk_gzip_finish_write(struct opkg_opk_gzip *gzip) -{ - /* Sanity check */ - if (gzip->dir != _OPKG_OPK_GZIP_DIR_WRITE) { - return OPKG_OPK_ERROR; - } - - if (gzip->written > 0 && _opkg_opk_gzip_write(gzip, NULL, 0, 1) != - OPKG_OPK_END) { - return OPKG_OPK_ERROR; - } - return OPKG_OPK_OK; -} - -int -opkg_opk_gzip_free(struct opkg_opk_gzip *gzip) -{ - int ret; - - ret = OPKG_OPK_OK; - if (gzip->dir == _OPKG_OPK_GZIP_DIR_READ) { - if (inflateEnd(&gzip->stream) != Z_OK) { - ret = OPKG_OPK_ERROR; - } - } else { - if (deflateEnd(&gzip->stream) != Z_OK) { - ret = OPKG_OPK_ERROR; - } - } - free(gzip); - return ret; -} diff --git a/src/gzip.h b/src/gzip.h deleted file mode 100644 index 2f91000..0000000 --- a/src/gzip.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#ifndef OPKG_OPK_GZIP_H_ -#define OPKG_OPK_GZIP_H_ - -#include <stdio.h> - -struct opkg_opk_gzip; - -typedef int (opkg_opk_gzip_read_func)(void *, char **, size_t *); - -/* - * Allocates and initializes a decompression structure. - * Parameters: - * - read: Function to read compressed data. Parameter 1 is user_data, - * parameter 2 is an address in which the read function should - * store an address to compressed data, and parameter 3 is an - * address in which the read function should store the size of read - * compressed data. Should return OPKG_OPK_OK if data is read, - * OPKG_OPK_END if no more data is available (end of file or - * archive), or OPKG_OPK_ERROR on error. - * - user_data: Passed to read function. - * Returns: - * - Allocated decompression structure on success. Free with - * opkg_opk_gzip_free(). - * - NULL on memory exhaustion. - */ -struct opkg_opk_gzip * -opkg_opk_gzip_init_read(opkg_opk_gzip_read_func *read_func, void *user_data); - -struct opkg_opk_gzip * -opkg_opk_gzip_init_write(FILE *write_fp); - -/* - * Reads and decompresses data to output the next record (512 octets). - * Parameters: - * - gzip: Decompression structure. - * - record: Address in which to store decompressed record. - * Returns: - * - OPKG_OPK_OK if a record is read and decompressed. - * - OPKG_OPK_END if the end of the gzip stream is reached. - * - OPKG_OPK_ERROR if the read function returned an error, the compressed input - * data or gzip stream end prematurely, or zlib returns an error. - */ -int -opkg_opk_gzip_read(struct opkg_opk_gzip *gzip, void *record); - -int -opkg_opk_gzip_write(struct opkg_opk_gzip *gzip, void *record, size_t size); - -size_t -opkg_opk_gzip_written(struct opkg_opk_gzip *gzip) __attribute__((__pure__)); - -int -opkg_opk_gzip_finish_write(struct opkg_opk_gzip *gzip); - -/* - * Frees a decompression structure. - * Parameters: - * - gzip: Decompression structure. - */ -int -opkg_opk_gzip_free(struct opkg_opk_gzip *gzip); - -#endif /* OPKG_OPK_GZIP_H_ */ diff --git a/src/i18n.h b/src/i18n.h deleted file mode 100644 index 4d8ee76..0000000 --- a/src/i18n.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifdef ENABLE_NLS - -#include <libintl.h> - -#define _(msgid) gettext(msgid) - -#else - -#define _(msgid) (msgid) - -#endif diff --git a/src/local.mk b/src/local.mk deleted file mode 100644 index 72f6ef4..0000000 --- a/src/local.mk +++ /dev/null @@ -1,16 +0,0 @@ -src_opkg_opk_SOURCES += \ - %reldir%/defs.h \ - %reldir%/dirent.c \ - %reldir%/dirent.h \ - %reldir%/gzip.c \ - %reldir%/gzip.h \ - %reldir%/i18n.h \ - %reldir%/main.c \ - %reldir%/opk.c \ - %reldir%/opk.h \ - %reldir%/specials.c \ - %reldir%/specials.h \ - %reldir%/ustar.c \ - %reldir%/ustar.h - -include %reldir%/opk/local.mk diff --git a/src/main.c b/src/main.c deleted file mode 100644 index b33c268..0000000 --- a/src/main.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#ifdef ENABLE_NLS -#include <locale.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include "defs.h" -#include "i18n.h" -#include "opk.h" - -#ifdef HAVE_GETOPT_LONG -#include <getopt.h> -#else -#include <unistd.h> -#endif - -extern const char *PACKAGE_VERSION_GIT; - -static const char *_OPTSTRING = "bc:d:s:f:F:lLhV"; -#ifdef HAVE_GETOPT_LONG -static const 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 = "special", - .has_arg = 1, - .flag = NULL, - .val = 's', - }, - { - .name = "control-file", - .has_arg = 1, - .flag = NULL, - .val = 'f', - }, - { - .name = "data-file", - .has_arg = 1, - .flag = NULL, - .val = 'F', - }, - { - .name = "list-control", - .has_arg = 0, - .flag = NULL, - .val = 'l', - }, - { - .name = "list-data", - .has_arg = 0, - .flag = NULL, - .val = 'L', - }, - { - .name = "help", - .has_arg = 0, - .flag = NULL, - .val = 'h', - }, - { - .name = "version", - .has_arg = 0, - .flag = NULL, - .val = 'V', - }, -}; -#endif - -static void -_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 [-s SPECIAL-FILE] " - "PACKAGE\n"), - program_name); -#ifdef HAVE_GETOPT_LONG - puts(_("Options:\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" -" -s, --special=SPECIAL-FILE Read device special files list from\n" -" SPECIAL-FILE.\n" -" -f, --control-file=CONTROL-FILE Print the contents of the named control " - "file.\n" -" If this option is given multiple times, the" - "\n" -" named control files will be printed in the" - "\n" -" order they appear in the package.\n" -" -F, --data-file=DATA-FILE Print the contents of the named data file." - "\n" -" If this option is given multiple times, the" - "\n" -" named data files will be printed in the " - "order\n" -" they appear in the package.\n" -" -l, --list-control List the control files.\n" -" -L, --list-data List the data files. The list is currently" - "\n" -" produced in a format similar to that\n" -" generated by GNU and BusyBox tar's verbose" - "\n" -" listing. User and group IDs and names are" - "\n" -" not checked against those on the host " - "system,\n" -" since they may differ.\n" -" -h, --help Show this help information and exit.\n" -" -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" -" -s Read device special files list from SPECIAL-FILE.\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" -" appear in the package.\n" -" -F Print the contents of the named data file. If this option is given\n" -" multiple times, the named data files will be printed in the order they\n" -" appear in the package.\n" -" -l List the control files.\n" -" -L List the data files. The list is currently produced in a format " - "similar\n" -" to that generated by GNU and BusyBox tar's verbose listing. User and\n" -" group IDs and names are not checked against those on the host system,\n" -" since they may differ.\n" -" -h Show this help information and exit.\n" -" -V Show version information and exit.")); -#endif -} - -static void -_version(void) -{ - printf("%s %s%s\n", PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_VERSION_GIT); - /* TRANSLATORS: The "%s" conversion specifications are the copyright - * year(s) and copyright holder(s), respectively. */ - printf(_("Copyright (C) %s %s\n"), "2023", "Patrick McDermott"); - puts(_("License GPLv3+: GNU GPL version 3 or later " - "<http://gnu.org/licenses/gpl.html>.\n" - "This is free software: you are free to change and " - "redistribute it.\n" - "There is NO WARRANTY, to the extent permitted by " - "law.\n")); - printf(_("Please report bugs to <%s>.\n"), PACKAGE_BUGREPORT); -} - -static void -_help_tip(const char *program_name) -{ - /* TRANSLATORS: The "%s" conversion specifications are the program name - * and help option, respectively. */ - fprintf(stderr, _("Try \"%s %s\" for more information\n"), program_name, -#ifdef HAVE_GETOPT_LONG - "--help" -#else - "-h" -#endif - ); -} - -static void -_opt_mutex(const char *program_name, char opt1, char opt2) -{ - fprintf(stderr, _("%s: Options -%c and -%c are mutually exclusive\n"), - program_name, opt1, opt2); - _help_tip(program_name); -} - -int -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; - int opt_L; - int opt; - -#ifdef ENABLE_NLS - bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); -#ifdef HAVE_BIND_TEXTDOMAIN_CODESET - bind_textdomain_codeset(PACKAGE, "UTF-8"); -#endif - textdomain(PACKAGE); - setlocale(LC_ALL, ""); -#endif - - program_name = argv[0]; - - /* Initialize package. */ - opk = opkg_opk_opk_init(); - if (opk == NULL) { - return EXIT_FAILURE; - } - - opterr = 0; - build = 0; - opt_f = 0; - opt_F = 0; - opt_l = 0; - opt_L = 0; -#ifdef HAVE_GETOPT_LONG - while ((opt = getopt_long(argc, argv, _OPTSTRING, _LONGOPTS, NULL)) - != -1) { -#else - 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 's': - if (opkg_opk_opk_specials_read(opk, optarg) != - OPKG_OPK_OK) { - fprintf(stderr, _("%s: Failed to read " - "specials file" - "\n"), - program_name); - opkg_opk_opk_free(opk); - return EXIT_FAILURE; - } - break; - case 'f': - if (opt_l > 0) { - _opt_mutex(program_name, 'f', 'l'); - opkg_opk_opk_free(opk); - return EXIT_FAILURE; - } - opt_f = 1; - if (opkg_opk_opk_print_control(opk, optarg) - != OPKG_OPK_OK) { - opkg_opk_opk_free(opk); - return EXIT_FAILURE; - } - break; - case 'F': - if (opt_L > 0) { - _opt_mutex(program_name, 'F', 'L'); - opkg_opk_opk_free(opk); - return EXIT_FAILURE; - } - opt_F = 1; - if (opkg_opk_opk_print_data(opk, optarg) - != OPKG_OPK_OK) { - opkg_opk_opk_free(opk); - return EXIT_FAILURE; - } - break; - case 'l': - if (opt_f > 0) { - _opt_mutex(program_name, 'f', 'l'); - opkg_opk_opk_free(opk); - return EXIT_FAILURE; - } - opt_l = 1; - opkg_opk_opk_list_control(opk); - break; - case 'L': - if (opt_F > 0) { - _opt_mutex(program_name, 'F', 'L'); - opkg_opk_opk_free(opk); - return EXIT_FAILURE; - } - opt_L = 1; - opkg_opk_opk_list_data(opk); - break; - case 'h': - _help(program_name); - opkg_opk_opk_free(opk); - return EXIT_SUCCESS; - case 'V': - _version(); - opkg_opk_opk_free(opk); - return EXIT_SUCCESS; - default: - fprintf(stderr, _("%s: Invalid option: " - "\"%c\"\n"), - program_name, optopt); - _help_tip(program_name); - opkg_opk_opk_free(opk); - return EXIT_FAILURE; - } - } - argc -= optind; - argv += optind; - - if (argc < 1) { - fprintf(stderr, _("%s: Missing package file operand\n"), - program_name); - _help_tip(program_name); - opkg_opk_opk_free(opk); - return EXIT_FAILURE; - } else if (argc > 1) { - fprintf(stderr, _("%s: Too many package file operands\n"), - program_name); - _help_tip(program_name); - 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); - return EXIT_SUCCESS; -} diff --git a/src/opk.c b/src/opk.c deleted file mode 100644 index 457f7fa..0000000 --- a/src/opk.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <stdlib.h> -#include <string.h> -#include "defs.h" -#include "specials.h" -#include "opk.h" -#include "opk/opk.h" - -struct opkg_opk_opk * -opkg_opk_opk_init(void) -{ - struct opkg_opk_opk *opk; - - opk = malloc(sizeof(*opk)); - if (opk == NULL) { - return NULL; - } - - opk->print_control_head = NULL; - opk->print_control_tail = NULL; - opk->print_data_head = NULL; - opk->print_data_tail = NULL; - opk->list_control = 0; - opk->list_data = 0; - opk->control_dir = NULL; - opk->specials = NULL; - opk->previously_printed = 0; - - return opk; -} - -static int -_opkg_opk_opk_add_seek_name(struct _opkg_opk_opk_seek_name **head, - struct _opkg_opk_opk_seek_name **tail, const char *name) -{ - struct _opkg_opk_opk_seek_name *new; - - new = malloc(sizeof(*new)); - if (new == NULL) { - return OPKG_OPK_ERROR; - } - if (name[0] == '.' && name[1] == '/') { - new->name = name + 2; - } else if (name[0] == '/') { - new->name = name + 1; - } else { - new->name = name; - } - - new->prev = *tail; - new->next = NULL; - - if (*head == NULL) { - *head = new; - } else { - (*tail)->next = new; - } - *tail = new; - - return OPKG_OPK_OK; -} - -int -opkg_opk_opk_print_control(struct opkg_opk_opk *opk, const char *name) -{ - return _opkg_opk_opk_add_seek_name(&opk->print_control_head, - &opk->print_control_tail, name); -} - -int -opkg_opk_opk_print_data(struct opkg_opk_opk *opk, const char *name) -{ - return _opkg_opk_opk_add_seek_name(&opk->print_data_head, - &opk->print_data_tail, name); -} - -int -opkg_opk_opk_list_control(struct opkg_opk_opk *opk) -{ - opk->list_control = 1; - return OPKG_OPK_OK; -} - -int -opkg_opk_opk_list_data(struct opkg_opk_opk *opk) -{ - opk->list_data = 1; - return OPKG_OPK_OK; -} - -int -opkg_opk_opk_control_dir(struct opkg_opk_opk *opk, const char *dir) -{ - opk->control_dir = dir; - opk->control_dir_len = strlen(dir); - return OPKG_OPK_OK; -} - -int -opkg_opk_opk_data_dir(struct opkg_opk_opk *opk, const char *dir) -{ - opk->data_dir = dir; - opk->data_dir_len = strlen(dir); - return OPKG_OPK_OK; -} - -int -opkg_opk_opk_specials_read(struct opkg_opk_opk *opk, const char *file_name) -{ - if (opkg_opk_specials_read(file_name, &opk->specials) != OPKG_OPK_OK) { - return OPKG_OPK_ERROR; - } - return OPKG_OPK_OK; -} - -void -opkg_opk_opk_free(struct opkg_opk_opk *opk) -{ - struct _opkg_opk_opk_seek_name *name; - - while (opk->print_control_head != NULL) { - name = opk->print_control_head; - opk->print_control_head = opk->print_control_head->next; - free(name); - } - while (opk->print_data_head != NULL) { - name = opk->print_data_head; - opk->print_data_head = opk->print_data_head->next; - free(name); - } - opkg_opk_specials_free(opk->specials); - free(opk); -} diff --git a/src/opk.h b/src/opk.h deleted file mode 100644 index c987431..0000000 --- a/src/opk.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#ifndef OPKG_OPK_OPK_H_ -#define OPKG_OPK_OPK_H_ - -#include "ustar.h" - -struct opkg_opk_opk; - -/* - * Allocates a package structure. Free with opkg_opk_opk_free(). - * Returns: - * - Allocated package structure on success. Free with opkg_opk_opk_free(). - * - NULL on memory exhaustion. - */ -struct opkg_opk_opk * -opkg_opk_opk_init(void); - -/* - * Adds a name to a list of control files to print when opkg_opk_opk_read() is - * called. - * Parameters: - * - opk: Package structure. - * - name: Name of control file to print. - * Returns: - * - OPKG_OPK_OK if the name was added to the list. - * - OPKG_OPK_ERROR on memory exhaustion. - */ -int -opkg_opk_opk_print_control(struct opkg_opk_opk *opk, const char *name); - -/* - * Adds a name to a list of data files to print when opkg_opk_opk_read() is - * called. - * Parameters: - * - opk: Package structure. - * - name: Name of data file to print. - * Returns: - * - OPKG_OPK_OK if the name was added to the list. - * - OPKG_OPK_ERROR on memory exhaustion. - */ -int -opkg_opk_opk_print_data(struct opkg_opk_opk *opk, const char *name); - -/* - * Lists control files when opkg_opk_opk_read() is called. - * Parameters: - * - opk: Package structure. - * Returns: - * - OPKG_OPK_OK. - */ -int -opkg_opk_opk_list_control(struct opkg_opk_opk *opk); - -/* - * Lists data files when opkg_opk_opk_read() is called. - * Parameters: - * - opk: Package structure. - * Returns: - * - OPKG_OPK_OK. - */ -int -opkg_opk_opk_list_data(struct opkg_opk_opk *opk); - -/* - * 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. - * Returns: - * - OPKG_OPK_OK. - */ -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); - -/* - * Reads types and device numbers of device special files from a list file for - * use when writing. - * Parameters: - * - opk: Package structure. - * - file_name: Device special files list file. - * Returns: - * - OPKG_OPK_OK if the list was successfully read. - * - OPKG_OPK_ERROR if list file is unreadable or malformed or on memory - * exhaustion. - */ -int -opkg_opk_opk_specials_read(struct opkg_opk_opk *opk, const char *file_name); - -/* - * Performs the configured read actions. - * Parameters: - * - file_name: Package's file name. - */ -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. - */ -void -opkg_opk_opk_free(struct opkg_opk_opk *opk); - -#endif /* OPKG_OPK_OPK_H_ */ diff --git a/src/opk/local.mk b/src/opk/local.mk deleted file mode 100644 index 9335153..0000000 --- a/src/opk/local.mk +++ /dev/null @@ -1,4 +0,0 @@ -src_opkg_opk_SOURCES += \ - %reldir%/opk.h \ - %reldir%/read.c \ - %reldir%/write.c diff --git a/src/opk/opk.h b/src/opk/opk.h deleted file mode 100644 index 93f9dfe..0000000 --- a/src/opk/opk.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#ifndef OPKG_OPK_OPK_OPK_H_ -#define OPKG_OPK_OPK_OPK_H_ - -#include <stdio.h> -#include "../gzip.h" -#include "../opk.h" -#include "../ustar.h" - -struct _opkg_opk_opk_seek_name { - const char *name; - struct _opkg_opk_opk_seek_name *prev; - struct _opkg_opk_opk_seek_name *next; -}; - -struct opkg_opk_opk { - struct _opkg_opk_opk_seek_name *print_control_head; - struct _opkg_opk_opk_seek_name *print_control_tail; - struct _opkg_opk_opk_seek_name *print_data_head; - struct _opkg_opk_opk_seek_name *print_data_tail; - int list_control; - int list_data; - const char *control_dir; - size_t control_dir_len; - const char *data_dir; - size_t data_dir_len; - FILE *file; - struct opkg_opk_specials *specials; - char file_buffer[8192]; - uint64_t mtime; - const char *file_name; - char *outer_uname; - char *outer_gname; - struct opkg_opk_gzip *outer_gzip; - struct opkg_opk_ustar *outer_ustar; - struct opkg_opk_gzip *inner_gzip; - struct opkg_opk_ustar *inner_ustar; - int previously_printed; - char *path_real; - char *path_virt; - char *temp_file_name; -}; - -#endif /* OPKG_OPK_OPK_OPK_H_ */ diff --git a/src/opk/read.c b/src/opk/read.c deleted file mode 100644 index 21fbc66..0000000 --- a/src/opk/read.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <time.h> -#include "../defs.h" -#include "../gzip.h" -#include "../i18n.h" -#include "../opk.h" -#include "../ustar.h" -#include "opk.h" - -static int -_opkg_opk_opk_read_file(void *user_data, char **buffer, size_t *size) -{ - struct opkg_opk_opk *opk = user_data; - - *buffer = opk->file_buffer; - *size = fread(opk->file_buffer, 1, sizeof(opk->file_buffer), - opk->file); - if (feof(opk->file)) { - return OPKG_OPK_END; - } else if (ferror(opk->file) || *size == 0) { - return OPKG_OPK_ERROR; - } else { - return OPKG_OPK_OK; - } -} - -static int -_opkg_opk_opk_read_init_inner(struct opkg_opk_opk *opk) -{ - /* Initialize inner gzip decompressor. */ - opk->inner_gzip = opkg_opk_gzip_init_read( - (opkg_opk_gzip_read_func *) &opkg_opk_ustar_read, - opk->outer_ustar); - if (opk->inner_gzip == NULL) { - fputs(_("Error: Failed to initialize\n"), stderr); - return OPKG_OPK_ERROR; - } - - /* Initialize inner ustar unarchiver. */ - opk->inner_ustar = opkg_opk_ustar_init(opk->inner_gzip); - if (opk->inner_ustar == NULL) { - fputs(_("Error: Failed to initialize\n"), stderr); - opkg_opk_gzip_free(opk->inner_gzip); - return OPKG_OPK_ERROR; - } - - return OPKG_OPK_OK; -} - -static void -_opkg_opk_opk_read_free_inner(struct opkg_opk_opk *opk) -{ - opkg_opk_ustar_free(opk->inner_ustar); - opkg_opk_gzip_free(opk->inner_gzip); -} - -static int -_opkg_opk_opk_read_check_name(const char *member_name, - struct _opkg_opk_opk_seek_name **head, - struct _opkg_opk_opk_seek_name **tail) -{ - struct _opkg_opk_opk_seek_name *seek_name; - - if (member_name[0] == '.' && member_name[1] == '/') { - member_name += 2; - } else if (member_name[0] == '/') { - member_name += 1; - } - - /* Check each requested name. */ - for (seek_name = *head; seek_name != NULL; seek_name = seek_name->next) - { - if (strcmp(member_name, seek_name->name) == 0) { - if (seek_name->prev != NULL) { - seek_name->prev->next = seek_name->next; - } else { - /* This was the head. Update. */ - *head = seek_name->next; - } - if (seek_name->next != NULL) { - seek_name->next->prev = seek_name->prev; - } else { - /* This was the tail. Update. */ - *tail = seek_name->prev; - } - free(seek_name); - return OPKG_OPK_OK; - } - } - - return OPKG_OPK_ERROR; /* Member not found */ -} - -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->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; - } -/* For below #pragmas: path initialized here - * (opk->control_dir != NULL). */ - 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_read_init_inner(opk) != OPKG_OPK_OK) { - if (opk->control_dir != NULL) { -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored \ - "-Wanalyzer-use-of-uninitialized-value" - free(path); -# pragma GCC diagnostic pop - } - return OPKG_OPK_ERROR; - } - - while ((ret_list = opkg_opk_ustar_list(opk->inner_ustar, &member)) == - OPKG_OPK_OK) { - /* 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; - } - - /* Only extract and/or print regular files. */ - if (member->type != '-') { - fputs(_("Error: Non-regular control files not supported" - "\n"), stderr); - free(member); - _opkg_opk_opk_read_free_inner(opk); - if (opk->control_dir != NULL) { -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored \ - "-Wanalyzer-use-of-uninitialized-value" - free(path); -# pragma GCC diagnostic pop - } - return OPKG_OPK_ERROR; - } - - /* Open file for extraction. */ - if (opk->control_dir != NULL) { -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored \ - "-Wanalyzer-use-of-uninitialized-value" - if (sprintf(path, "%s/%s", opk->control_dir, - member->name) <= 0) { - free(member); - _opkg_opk_opk_read_free_inner(opk); - free(path); - return OPKG_OPK_ERROR; -# pragma GCC diagnostic pop - } -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored \ - "-Wmaybe-uninitialized" -/* For below #pragmas: fp initialized here - * (opk->control_dir != NULL). */ -/* GCC analyzer doesn't complain about this use of path? */ - fp = fopen(path, "wb"); -# pragma GCC diagnostic pop - if (fp == NULL) { - fputs(_("Error: Failed to extract control file" - "\n"), stderr); - free(member); - _opkg_opk_opk_read_free_inner(opk); -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored \ - "-Wanalyzer-use-of-uninitialized-value" - free(path); -# pragma GCC diagnostic pop - return OPKG_OPK_ERROR; - } - } - - /* List file. */ - if (opk->list_control > 0) { - puts(buffer); - opk->previously_printed = 1; - } - - /* Print file if requested. */ - if (opk->print_control_head != NULL && - _opkg_opk_opk_read_check_name(member->name, - &opk->print_control_head, - &opk->print_control_tail) == - OPKG_OPK_OK) { - /* Name requested for printing. */ - print = 1; - } else { - print = 0; - } - free(member); - if (print == 1 && opk->previously_printed == 1) { - puts(""); - } - while ((ret_read = opkg_opk_ustar_read(opk->inner_ustar, - &buffer, &size)) == OPKG_OPK_OK) - { - if (print == 1 && fwrite(buffer, 1, size, stdout) != - size) { - fputs(_("Error: Failed to print control file\n") - , stderr); - _opkg_opk_opk_read_free_inner(opk); - if (opk->control_dir != NULL) { - free(path); - } - return OPKG_OPK_ERROR; - } -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored \ - "-Wanalyzer-use-of-uninitialized-value" - if (opk->control_dir != NULL && fwrite(buffer, 1, size, - fp) != size) { - fputs(_("Error: Failed to write control file\n") - , stderr); - _opkg_opk_opk_read_free_inner(opk); - free(path); -# pragma GCC diagnostic pop - return OPKG_OPK_ERROR; - } - } - if (ret_read == OPKG_OPK_ERROR) { - fputs(_("Error: Failed to read control file\n"), - stderr); - _opkg_opk_opk_read_free_inner(opk); - if (opk->control_dir != NULL) { -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored \ - "-Wanalyzer-use-of-uninitialized-value" -# pragma GCC diagnostic ignored \ - "-Wmaybe-uninitialized" - free(path); - fclose(fp); -# pragma GCC diagnostic pop - } -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wanalyzer-file-leak" - return OPKG_OPK_ERROR; -# pragma GCC diagnostic pop - } - opk->previously_printed = 1; - - /* Close file for extraction. */ - if (opk->control_dir != NULL) { -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored \ - "-Wanalyzer-use-of-uninitialized-value" - if (fclose(fp) != 0) { - _opkg_opk_opk_read_free_inner(opk); - free(path); -# pragma GCC diagnostic pop - return OPKG_OPK_ERROR; - } - } - } - if (opk->control_dir != NULL) { - /* Done with path buffer. */ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored \ - "-Wanalyzer-use-of-uninitialized-value" - free(path); -# pragma GCC diagnostic pop - } - if (ret_list == OPKG_OPK_ERROR) { - fputs(_("Error: Failed to list control files\n"), stderr); - _opkg_opk_opk_read_free_inner(opk); - return OPKG_OPK_ERROR; - } - - /* Check for files not found. */ - if (opk->print_control_head != NULL) { - for (seek_name = opk->print_control_head; seek_name != NULL; - seek_name = seek_name->next) { - fprintf(stderr, _("Error: Failed to find control file " - "\"%s\"\n"), seek_name->name); - } - _opkg_opk_opk_read_free_inner(opk); - return OPKG_OPK_ERROR; - } - - _opkg_opk_opk_read_free_inner(opk); - - return OPKG_OPK_OK; -} - -static int -_opkg_opk_opk_read_data(struct opkg_opk_opk *opk) -{ - struct opkg_opk_ustar_member *head; - struct opkg_opk_ustar_member *tail; - struct opkg_opk_ustar_member *member; - int ret; - size_t uname_len; - size_t uname_len_max; - size_t gname_len; - size_t gname_len_max; - uint64_t size_max; - uint32_t devmajor_max; - uint32_t devminor_max; - int ret_read; - char *buffer; - size_t size; - long int size_len_max; - long int devmajor_len_max; - long int devminor_len_max; - long int dev_len_max; - char fmt[26]; - /* "%c%s %-32s/%-32s %16d %s " */ - char fmt_dev[30]; - /* "%c%s %-32s/%-32s %9d, %7d %s " */ - int len; - char mode[10]; - char mtime[20]; - - if (opk->list_data == 0 && opk->print_data_head == NULL) { - /* Not listing or printing any data files. */ - return OPKG_OPK_OK; - } - - if (_opkg_opk_opk_read_init_inner(opk) != OPKG_OPK_OK) { - return OPKG_OPK_ERROR; - } - - /* Build singly-linked list and find maximum column widths. */ - head = NULL; - tail = NULL; - uname_len_max = 0; - gname_len_max = 0; - size_max = 0; - devmajor_max = 0; - devminor_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; - } else { - tail->next = member; - } - tail = member; - uname_len = strlen(member->uname); - if (uname_len > uname_len_max) { - uname_len_max = uname_len; - } - gname_len = strlen(member->gname); - if (gname_len > gname_len_max) { - gname_len_max = gname_len; - } - if (member->size > size_max) { - size_max = member->size; - } - if (member->devmajor > devmajor_max) { - devmajor_max = member->devmajor; - } - if (member->devminor > devminor_max) { - devminor_max = member->devminor; - } - } - - if (opk->print_data_head == NULL) { - if (opk->list_data == 0) { - free(member); - } - continue; - } - if (_opkg_opk_opk_read_check_name(member->name, - &opk->print_data_head, - &opk->print_data_tail) != - OPKG_OPK_OK) { - /* Name not requested for printing. */ - if (opk->list_data == 0) { - free(member); - } - continue; - } - if (opk->list_data == 0) { - free(member); - } - if (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) { - fputs(_("Error: Failed to print data file\n") - , stderr); - _opkg_opk_opk_read_free_inner(opk); - return OPKG_OPK_ERROR; - } - } - if (ret_read == OPKG_OPK_ERROR) { - fputs(_("Error: Failed to read data file\n"), - stderr); - _opkg_opk_opk_read_free_inner(opk); - return OPKG_OPK_ERROR; - } - opk->previously_printed = 1; - } - if (ret == OPKG_OPK_ERROR) { - fputs(_("Error: Failed to list data files\n"), stderr); - _opkg_opk_opk_read_free_inner(opk); - return OPKG_OPK_ERROR; - } - if (tail != NULL) { - tail->next = NULL; - } - - if (opk->list_data == 0) { - _opkg_opk_opk_read_free_inner(opk); - return OPKG_OPK_OK; - } - - /* Print and free members. */ - if (opk->previously_printed == 1) { - puts(""); - } - ret = OPKG_OPK_OK; - size_len_max = lrint(ceil(log10( size_max))); - devmajor_len_max = lrint(ceil(log10(devmajor_max))); - devminor_len_max = lrint(ceil(log10(devminor_max))); - if (devmajor_len_max == 0) { - devmajor_len_max = 1; - } - if (devminor_len_max == 0) { - devminor_len_max = 1; - } - dev_len_max = devmajor_len_max + 2 /* ", " */ + devminor_len_max; - if (dev_len_max > size_len_max) { - size_len_max = dev_len_max; - } - snprintf(fmt , sizeof(fmt ), "%%c%%s %%-%zus/%%-%zus %%%lid %%s ", - uname_len_max, gname_len_max, size_len_max); - snprintf(fmt_dev, sizeof(fmt_dev), "%%c%%s %%-%zus/%%-%zus " - "%%%lid, %%%lid %%s ", - uname_len_max, gname_len_max, - size_len_max - devminor_len_max - 2, devminor_len_max); - len = 34 + uname_len_max + gname_len_max + size_len_max; - for (member = head; member != NULL;) { - if (member->mode & 00400) mode[0] = 'r'; else mode[0] = '-'; - if (member->mode & 00200) mode[1] = 'w'; else mode[1] = '-'; - if (member->mode & 00100) mode[2] = 'x'; else mode[2] = '-'; - if (member->mode & 04000) mode[2] = 's'; - if (member->mode & 00040) mode[3] = 'r'; else mode[3] = '-'; - if (member->mode & 00020) mode[4] = 'w'; else mode[4] = '-'; - if (member->mode & 00010) mode[5] = 'x'; else mode[5] = '-'; - if (member->mode & 02000) mode[5] = 's'; - if (member->mode & 00004) mode[6] = 'r'; else mode[6] = '-'; - if (member->mode & 00002) mode[7] = 'w'; else mode[7] = '-'; - if (member->mode & 00001) mode[8] = 'x'; else mode[8] = '-'; - if (member->mode & 01000) mode[8] = 't'; - mode[9] = '\0'; - strftime(mtime, sizeof(mtime), "%Y-%m-%d %H:%M:%S", - localtime((const time_t *) &member->mtime)); -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wformat-nonliteral" - if (member->type != 'b' && member->type != 'c') { - if (printf(fmt, member->type, mode, - member->uname, member->gname, - member->size, mtime) != len) { - ret = OPKG_OPK_ERROR; - } - } else { - if (printf(fmt_dev, member->type, mode, - member->uname, member->gname, - member->devmajor, member->devminor, - mtime) != len) { - ret = OPKG_OPK_ERROR; - } - } -# pragma GCC diagnostic pop - /* Print name, ensuring it begins with "/". */ - if (member->name[0] == '.' && member->name[1] == '/') { - if (fputs(member->name + 1, stdout) == EOF) { - ret = OPKG_OPK_ERROR; - } - } else { - if (member->name[0] != '/' && putchar('/') == EOF) { - ret = OPKG_OPK_ERROR; - } - if (fputs(member->name, stdout) == EOF) { - ret = OPKG_OPK_ERROR; - } - } - /* Print link name, if any. */ - if (member->type == 'l' && printf(" -> %s", member->linkname) != - (int) (strlen(member->linkname) + 4)) { - ret = OPKG_OPK_ERROR; - } - if (puts("") == EOF) { - ret = OPKG_OPK_ERROR; - } - head = member; - member = member->next; - free(head); - } - - opk->previously_printed = 1; - - _opkg_opk_opk_read_free_inner(opk); - - return ret; -} - -int -opkg_opk_opk_read(struct opkg_opk_opk *opk, const char *file_name) -{ - int ret; - struct opkg_opk_ustar_member *member; - char *version_buffer; - size_t version_size; - - ret = OPKG_OPK_OK; - - /* Open outer archive. */ - opk->file = fopen(file_name, "rb"); - 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_read(&_opkg_opk_opk_read_file, - opk); - if (opk->outer_gzip == NULL) { - fputs(_("Error: Failed to initialize\n"), stderr); - ret = OPKG_OPK_ERROR; - goto out1; - } - - /* 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; - } - - /* Check package version. */ - if (opkg_opk_ustar_list(opk->outer_ustar, &member) != OPKG_OPK_OK) { - fputs(_("Error: Failed to find \"debian-binary\" in archive\n"), - stderr); - ret = OPKG_OPK_ERROR; - goto out3; - } - if (strcmp(member->name, "debian-binary") != 0) { - free(member); - fputs(_("Error: Failed to find \"debian-binary\" in archive\n"), - stderr); - ret = OPKG_OPK_ERROR; - goto out3; - } - free(member); - if (opkg_opk_ustar_read(opk->outer_ustar, - &version_buffer, &version_size) != - OPKG_OPK_OK) { - fputs(_("Error: Failed to read \"debian-binary\" in archive\n"), - stderr); - ret = OPKG_OPK_ERROR; - goto out3; - } - if (version_size < 4 || strncmp(version_buffer, "2.", 2) != 0) { - fputs(_("Error: Unsupported package version\n"), stderr); - ret = OPKG_OPK_ERROR; - goto out3; - } - - /* Read control archive. */ - if (opkg_opk_ustar_list(opk->outer_ustar, &member) != OPKG_OPK_OK) { - fputs(_("Error: Failed to find \"control.tar.gz\" in archive\n") - , stderr); - return OPKG_OPK_ERROR; - } - if (strcmp(member->name, "control.tar.gz") != 0) { - free(member); - fputs(_("Error: Failed to find \"control.tar.gz\" in archive\n") - , stderr); - return OPKG_OPK_ERROR; - } - free(member); - if (_opkg_opk_opk_read_control(opk) != OPKG_OPK_OK) { - ret = OPKG_OPK_ERROR; - goto out3; - } - - /* Read data archive. */ - if (opkg_opk_ustar_list(opk->outer_ustar, &member) != OPKG_OPK_OK) { - fputs(_("Error: Failed to find \"data.tar.gz\" in archive\n"), - stderr); - return OPKG_OPK_ERROR; - } - if (strcmp(member->name, "data.tar.gz") != 0) { - free(member); - fputs(_("Error: Failed to find \"data.tar.gz\" in archive\n"), - stderr); - return OPKG_OPK_ERROR; - } - free(member); - if (_opkg_opk_opk_read_data(opk) != OPKG_OPK_OK) { - 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; -} diff --git a/src/opk/write.c b/src/opk/write.c deleted file mode 100644 index 284b625..0000000 --- a/src/opk/write.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <dirent.h> -#include <grp.h> -#include <pwd.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/sysmacros.h> -#include <unistd.h> -#include "../defs.h" -#include "../dirent.h" -#include "../gzip.h" -#include "../i18n.h" -#include "../opk.h" -#include "../specials.h" -#include "../ustar.h" -#include "opk.h" - -enum _opkg_opk_opk_archive_type { - OPKG_OPK_OPK_ARCHIVE_TYPE_CONTROL_ = 0, - OPKG_OPK_OPK_ARCHIVE_TYPE_DATA_ = 1, -}; -static const char *OPKG_OPK_OPK_ARCHIVE_NAMES_[] = { - "control.tar.gz", - "data.tar.gz", -}; - -static int -_opkg_opk_opk_source_date_epoch(uint64_t *mtime) -{ - char *env; - char *end; - - env = getenv("SOURCE_DATE_EPOCH"); - if (env == NULL) { - return OPKG_OPK_ERROR; - } - *mtime = strtol(env, &end, 10); - if (*end != '\0') { - return OPKG_OPK_ERROR; - } - return OPKG_OPK_OK; -} - -static int -_opkg_opk_opk_write_filter(const struct dirent *de) -{ - if (de->d_name[0] == '.') { - if (de->d_name[1] == '\0') { - return 0; - } - if (de->d_name[1] == '.' && de->d_name[2] == '\0') { - return 0; - } - } - return 1; -} - -static int -_opkg_opk_opk_write_compar(const struct dirent **a, const struct dirent **b) -{ - return strcmp((*a)->d_name, (*b)->d_name); -} - -static int -_opkg_opk_opk_write_dir_read(struct opkg_opk_opk *opk, - struct opkg_opk_dirent *dir, size_t path_off) -{ - char *child_path; - int children_n; - struct dirent **children; - int children_i; - struct opkg_opk_dirent child; - size_t name_i; - struct stat st; - uid_t uid; - char *uname; - gid_t gid; - char *gname; - /* Extra byte (in macro definition) to detect - * overflow, not for NUL */ - char link[OPKG_OPK_USTAR_LINKNAME_SIZE]; - ssize_t link_len; - char type; - uint32_t devmajor; - uint32_t devminor; - FILE *fp; - char *buffer; - size_t size; - size_t num_read; - size_t tot_read; - int ret; - - child_path = opk->path_virt + path_off; - children_n = scandir(opk->path_real, &children, _opkg_opk_opk_write_filter, - _opkg_opk_opk_write_compar); - for (children_i = 0; children_i < children_n; ++children_i) { - child.name = children[children_i]->d_name; - child.parent = dir; - for (name_i = 0; children[children_i]->d_name[name_i] != '\0'; - ++name_i) { - if (path_off + name_i + 1 == OPKG_OPK_USTAR_NAME_SIZE) { - fprintf(stderr, "Error: File name \"%s\" too " - "long", - children[children_i]->d_name); - goto err; - } - child_path[name_i] = - children[children_i]->d_name[name_i]; - } - child_path[name_i] = '\0'; - if (lstat(opk->path_real, &st) != 0) { - fprintf(stderr, _("Error: Failed to stat \"%s\"\n"), - opk->path_real); - goto err; - } - /* TODO: Ownership override */ - uid = st.st_uid; - uname = getpwuid(uid)->pw_name; - gid = st.st_gid; - gname = getgrgid(gid)->gr_name; - if (S_ISDIR(st.st_mode)) { - if (path_off + name_i + 2 == OPKG_OPK_USTAR_NAME_SIZE) { - fprintf(stderr, "Error: File name \"%s\" too " - "long", child_path); - goto err; - } - child_path[name_i] = '/'; - child_path[++name_i] = '\0'; - if (opkg_opk_ustar_write_header(opk->inner_ustar, - &child, st.st_mode & 0777, - uid, uname, gid, gname, 0, 0, 0, - opk->mtime, 'd', NULL) != - OPKG_OPK_OK) { - fputs(_("Error: Failed to write header\n"), - stderr); - goto err; - } - if (_opkg_opk_opk_write_dir_read(opk, &child, - path_off + name_i) != - OPKG_OPK_OK) { - goto err; - } - } else if (S_ISLNK(st.st_mode)) { - link_len = readlink(opk->path_real, link, - OPKG_OPK_USTAR_LINKNAME_SIZE); - if (link_len < 0) { - goto err; - } - if (link_len == OPKG_OPK_USTAR_LINKNAME_SIZE) { - goto err; - } - link[link_len] = '\0'; - if (opkg_opk_ustar_write_header(opk->inner_ustar, - &child, 0777, - uid, uname, gid, gname, 0, 0, 0, - opk->mtime, 'l', link) != - OPKG_OPK_OK) { - fputs(_("Error: Failed to write header\n"), - stderr); - goto err; - } - } else if (S_ISCHR(st.st_mode)) { - if (opkg_opk_ustar_write_header(opk->inner_ustar, - &child, st.st_mode & 0777, - uid, uname, gid, gname, - major(st.st_rdev), - minor(st.st_rdev), - 0, opk->mtime, 'c', NULL) != - OPKG_OPK_OK) { - fputs(_("Error: Failed to write header\n"), - stderr); - goto err; - } - } else if (S_ISBLK(st.st_mode)) { - if (opkg_opk_ustar_write_header(opk->inner_ustar, - &child, st.st_mode & 0777, - uid, uname, gid, gname, - major(st.st_rdev), - minor(st.st_rdev), - 0, opk->mtime, 'b', NULL) != - OPKG_OPK_OK) { - fputs(_("Error: Failed to write header\n"), - stderr); - goto err; - } - } else if (S_ISFIFO(st.st_mode)) { - if (opkg_opk_ustar_write_header(opk->inner_ustar, - &child, st.st_mode & 0777, - uid, uname, gid, gname, 0, 0, 0, - opk->mtime, 'p', NULL) != - OPKG_OPK_OK) { - fputs(_("Error: Failed to write header\n"), - stderr); - goto err; - } - } else if (S_ISREG(st.st_mode)) { - if (opkg_opk_specials_find(opk->specials, - opk->path_virt, &type, - &devmajor, &devminor) == - OPKG_OPK_OK) { - if (opkg_opk_ustar_write_header( - opk->inner_ustar, - &child, - st.st_mode & 0777, - uid, uname, gid, gname, - devmajor, devminor, 0, - opk->mtime, type, NULL) - != OPKG_OPK_OK) { - fputs(_("Error: Failed to write header" - "\n"), stderr); - goto err; - } - continue; - } - if (opkg_opk_ustar_write_header(opk->inner_ustar, - &child, st.st_mode & 0777, - uid, uname, gid, gname, 0, 0, - st.st_size, opk->mtime, '-', - NULL) != OPKG_OPK_OK) { - fputs(_("Error: Failed to write header\n"), - stderr); - goto err; - } - fp = fopen(opk->path_real, "rb"); - if (fp == NULL) { - fprintf(stderr, _("Error: Failed to open file " - "\"%s\"\n"), - opk->path_real); - goto err; - } - opkg_opk_ustar_get_buffer(opk->inner_ustar, - &buffer, &size); - tot_read = 0; - while ((num_read = fread(buffer, 1, size, fp)) > 0) { - opkg_opk_ustar_write_data(opk->inner_ustar, - num_read); - tot_read += num_read; - } - if (ferror(fp) != 0) { - fputs(_("Error: Error reading file\n"), stderr); - fclose(fp); - goto err; - } - if (fclose(fp) != 0) { - fputs(_("Error: Failed to close file\n"), - stderr); - goto err; - } - if ((uintmax_t) tot_read != (uintmax_t) st.st_size) { - fprintf(stderr, _("Error: Expected %jd bytes " - "but read %zu\n"), - (intmax_t) st.st_size, - num_read); - goto err; - } - } else { - fprintf(stderr, _("Error: Unknown type of file \"%s\"\n" - ), opk->path_real); - goto err; - } - } - - ret = OPKG_OPK_OK; - goto out; - err: - ret = OPKG_OPK_ERROR; - out: - for (children_i = 0; children_i < children_n; ++children_i) { - free(children[children_i]); - } - free(children); - return ret; -} - -static int -_opkg_opk_opk_build_inner_archive(struct opkg_opk_opk *opk, - enum _opkg_opk_opk_archive_type archive_type) -{ - FILE *fp; - struct opkg_opk_dirent dirent; - struct stat st; - uid_t uid; - char *uname; - gid_t gid; - char *gname; - size_t written; - char *buffer; - size_t size; - size_t num_read; - size_t tot_read; - - /* Initialize inner gzip compressor. */ - if (sprintf(opk->temp_file_name, "%s~%s", opk->file_name, - OPKG_OPK_OPK_ARCHIVE_NAMES_[archive_type]) <= 0) - { - goto err0; - } - fp = fopen(opk->temp_file_name, "w+b"); - if (fp == NULL) { - fprintf(stderr, _("Error: Failed to open file \"%s\"\n"), - opk->temp_file_name); - goto err0; - } - opk->inner_gzip = opkg_opk_gzip_init_write(fp); - if (opk->inner_gzip == NULL) { - fputs(_("Error: Failed to initialize compressor\n"), stderr); - goto err1; - } - - /* Initialize inner ustar archiver. */ - opk->inner_ustar = opkg_opk_ustar_init(opk->inner_gzip); - if (opk->inner_ustar == NULL) { - fputs(_("Error: Failed to initialize archiver\n"), stderr); - goto err2; - } - - /* Write inner archive to temporary file. */ - dirent.name = "."; - dirent.parent = NULL; - if (archive_type == OPKG_OPK_OPK_ARCHIVE_TYPE_CONTROL_) { - sprintf(opk->path_real, "%s/", opk->control_dir); - opk->path_virt = opk->path_real + opk->control_dir_len; - } else { - sprintf(opk->path_real, "%s/", opk->data_dir); - opk->path_virt = opk->path_real + opk->data_dir_len; - } - if (stat(opk->path_real, &st) != 0) { - fprintf(stderr, _("Error: Failed to stat \"%s\"\n"), - opk->path_real); - goto err3; - } - uid = st.st_uid; - uname = getpwuid(uid)->pw_name; - gid = st.st_gid; - gname = getgrgid(gid)->gr_name; - if (opkg_opk_ustar_write_header(opk->inner_ustar, &dirent, - st.st_mode & 0777, uid, uname, gid, gname, 0, - 0, 0, opk->mtime, 'd', NULL) != OPKG_OPK_OK) { - fputs(_("Error: Failed to write header\n"), - stderr); - goto err3; - } - if (_opkg_opk_opk_write_dir_read(opk, &dirent, 1 /* Skip '/' */) != - OPKG_OPK_OK) { - goto err3; - } - - /* Write trailer. */ - if (opkg_opk_ustar_write_trailer(opk->inner_ustar) != OPKG_OPK_OK) { - fputs(_("Error: Failed to write trailer\n"), stderr); - goto err3; - } - - /* Finish inner archive. */ - opkg_opk_ustar_free(opk->inner_ustar); - opkg_opk_gzip_finish_write(opk->inner_gzip); - written = opkg_opk_gzip_written(opk->inner_gzip); - opkg_opk_gzip_free(opk->inner_gzip); - - /* Write header in outer archive. */ - dirent.name = OPKG_OPK_OPK_ARCHIVE_NAMES_[archive_type]; - dirent.parent = NULL; - if (opkg_opk_ustar_write_header(opk->outer_ustar, &dirent, 0644, - 0, opk->outer_uname, 0, opk->outer_gname, 0, 0, - written, opk->mtime, '-', NULL) != - OPKG_OPK_OK) { - fputs(_("Error: Failed to write header\n"), stderr); - goto err1; - } - - /* Read temporary file into outer archive. */ - if (fseek(fp, 0L, SEEK_SET) != 0) { - fputs(_("Error: Failed to seek in file\n"), stderr); - goto err1; - } - opkg_opk_ustar_get_buffer(opk->outer_ustar, &buffer, &size); - tot_read = 0; - while ((num_read = fread(buffer, 1, size, fp)) > 0) { - opkg_opk_ustar_write_data(opk->outer_ustar, num_read); - tot_read += num_read; - } - if (ferror(fp) != 0) { - fputs(_("Error: Error reading file\n"), stderr); - fclose(fp); - goto err1; - } - if (fclose(fp) != 0) { - fputs(_("Error: Failed to close file\n"), stderr); - goto err1; - } - unlink(opk->temp_file_name); - if (tot_read != written) { - fprintf(stderr, _("Error: Wrote %lu bytes but read %lu\n"), - written, num_read); - goto err1; - } - - return OPKG_OPK_OK; - - err3: - opkg_opk_ustar_free(opk->inner_ustar); - err2: - opkg_opk_gzip_free(opk->inner_gzip); - err1: - fclose(fp); - err0: - 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; - size_t path_len; - - ret = OPKG_OPK_OK; - - if (_opkg_opk_opk_source_date_epoch(&opk->mtime) == OPKG_OPK_ERROR) { - fputs(_("Error: Missing or invalid SOURCE_DATE_EPOCH\n"), - stderr); - ret = OPKG_OPK_ERROR; - goto out0; - } - - opk->file_name = file_name; - - /* 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 compressor. */ - opk->outer_gzip = opkg_opk_gzip_init_write(opk->file); - if (opk->outer_gzip == NULL) { - fputs(_("Error: Failed to initialize\n"), stderr); - ret = OPKG_OPK_ERROR; - goto out1; - } - - /* Initialize outer ustar archiver. */ - 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; - } - - opk->outer_uname = getpwuid(0)->pw_name; - opk->outer_gname = getgrgid(0)->gr_name; - - /* Write version file. */ - dirent.name = "debian-binary"; - dirent.parent = NULL; - if (opkg_opk_ustar_write_header(opk->outer_ustar, &dirent, 0644, - 0, opk->outer_uname, 0, opk->outer_gname, 0, 0, - 4, opk->mtime, '-', 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; - } - - /* Allocate control and data file path buffer. */ - if (opk->control_dir_len >= opk->data_dir_len) { - path_len = opk->control_dir_len; - } else { - path_len = opk->data_dir_len; - } - path_len += 1 /* '/' */ + OPKG_OPK_USTAR_NAME_SIZE; - opk->path_real = malloc(path_len); - if (opk->path_real == NULL) { - ret = OPKG_OPK_ERROR; - goto out3; - } - - /* Allocate temporary archive file name buffer. */ - opk->temp_file_name = - malloc(strlen(file_name) + strlen("~control.tar.gz") + 1); - if (opk->temp_file_name == NULL) { - ret = OPKG_OPK_ERROR; - goto out4; - } - - if (_opkg_opk_opk_build_inner_archive(opk, - OPKG_OPK_OPK_ARCHIVE_TYPE_CONTROL_) != - OPKG_OPK_OK) { - ret = OPKG_OPK_ERROR; - goto out5; - } - if (_opkg_opk_opk_build_inner_archive(opk, - OPKG_OPK_OPK_ARCHIVE_TYPE_DATA_) != - OPKG_OPK_OK) { - ret = OPKG_OPK_ERROR; - goto out5; - } - - /* 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 out5; - } - - out5: - free(opk->temp_file_name); - out4: - free(opk->path_real); - out3: - opkg_opk_ustar_free(opk->outer_ustar); - out2: - opkg_opk_gzip_finish_write(opk->outer_gzip); - opkg_opk_gzip_free(opk->outer_gzip); - out1: - fclose(opk->file); - out0: - return ret; -} diff --git a/src/specials.c b/src/specials.c deleted file mode 100644 index b13ff86..0000000 --- a/src/specials.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <inttypes.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "defs.h" -#include "specials.h" - -struct opkg_opk_specials { - char type; - uint32_t devmajor; - uint32_t devminor; - char *name; - struct opkg_opk_specials *next; -}; - -static int -_opkg_opk_specials_read_v1(FILE *fp, struct opkg_opk_specials **specials) -{ - struct opkg_opk_specials *special; - - *specials = NULL; - fscanf(fp, "%*[^\n]\n"); /* Header line */ - while (feof(fp) == 0) { - special = malloc(sizeof(*special)); - if (special == NULL) { - opkg_opk_specials_free(*specials); - return OPKG_OPK_ERROR; - } -/* POSIX specifies the assignment-allocation character 'm', but ISO - * C doesn't, so GCC prints a warning. */ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wformat" - if (fscanf(fp, " %c %" SCNu32 " %" SCNu32 " %ms \n", - &special->type, - &special->devmajor, &special->devminor, - &special->name) != 4) { -# pragma GCC diagnostic pop - opkg_opk_specials_free(*specials); - return OPKG_OPK_ERROR; - } - if (special->type != 'c' && special->type != 'b') { - opkg_opk_specials_free(*specials); - return OPKG_OPK_ERROR; - } - special->next = *specials; - *specials = special; - } - - return OPKG_OPK_OK; -} - -int -opkg_opk_specials_read(const char *file_name, - struct opkg_opk_specials **specials) -{ - FILE *fp; - unsigned int version; - - fp = fopen(file_name, "r"); - if (fp == NULL) { - return OPKG_OPK_ERROR; - } - if (fscanf(fp, " version = %u \n", &version) != 1) { - fclose(fp); - return OPKG_OPK_ERROR; - } - switch (version) { - case 1U: - if (_opkg_opk_specials_read_v1(fp, specials) != - OPKG_OPK_OK) { - fclose(fp); - return OPKG_OPK_ERROR; - } - break; - default: - fclose(fp); - return OPKG_OPK_ERROR; - } - - fclose(fp); /* Just reading, so OK to ignore errors */ - return OPKG_OPK_OK; -} - -int -opkg_opk_specials_find(struct opkg_opk_specials *specials, const char *find, - char *type, uint32_t *devmajor, uint32_t *devminor) -{ - for (; specials != NULL; specials = specials->next) { - if (strcmp(find, specials->name) == 0) { - *type = specials->type; - *devmajor = specials->devmajor; - *devminor = specials->devminor; - return OPKG_OPK_OK; - } - } - - return OPKG_OPK_END; -} - -void -opkg_opk_specials_free(struct opkg_opk_specials *specials) -{ - struct opkg_opk_specials *special; - - while (specials != NULL) { - special = specials; - specials = specials->next; - free(special->name); - free(special); - } -} diff --git a/src/specials.h b/src/specials.h deleted file mode 100644 index f69ae51..0000000 --- a/src/specials.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#ifndef OPKG_OPK_SPECIALS_H_ -#define OPKG_OPK_SPECIALS_H_ - -#include <stdint.h> - -struct opkg_opk_specials; - -int -opkg_opk_specials_read(const char *file_name, - struct opkg_opk_specials **specials); - -int -opkg_opk_specials_find(struct opkg_opk_specials *specials, const char *find, - char *type, uint32_t *devmajor, uint32_t *devminor); - -void -opkg_opk_specials_free(struct opkg_opk_specials *specials); - -#endif /* OPKG_OPK_SPECIALS_H_ */ diff --git a/src/ustar.c b/src/ustar.c deleted file mode 100644 index 2b26ed1..0000000 --- a/src/ustar.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "defs.h" -#include "dirent.h" -#include "gzip.h" -#include "ustar.h" - -#define OPKG_OPK_USTAR_NUM_BASE_ 8 - -/* #define OPKG_OPK_USTAR_BB_EXACT_HEADER_ 1 */ - -struct _opkg_opk_ustar_header { - char name [100]; - char mode [8]; - char uid [8]; - char gid [8]; - char size [12]; - char mtime [12]; - char chksum [8]; - char typeflag [1]; - char linkname [100]; - char magic [6]; - char version [2]; - char uname [32]; - char gname [32]; - char devmajor [8]; - char devminor [8]; - char prefix [155]; - char padding [12]; -} __attribute__((__packed__)); - -struct opkg_opk_ustar { - struct opkg_opk_gzip *gzip; - uint64_t data_size_remaining; - struct _opkg_opk_ustar_header header; - char record[OPKG_OPK_USTAR_RECORD_SIZE]; -}; - -struct opkg_opk_ustar * -opkg_opk_ustar_init(struct opkg_opk_gzip *gzip) -{ - struct opkg_opk_ustar *ustar; - - ustar = malloc(sizeof(*ustar)); - if (ustar == NULL) { - return NULL; - } - - ustar->gzip = gzip; - ustar->data_size_remaining = 0; - - return ustar; -} - -static int -_opkg_opk_ustar_next(struct opkg_opk_ustar *ustar) -{ - char *end; - uint32_t chksum_got; - uint32_t chksum_exp; - size_t i; - unsigned char *header_uc; - - /* Seek through data records until next header record. */ - while (ustar->data_size_remaining > 0) { - if (opkg_opk_ustar_read(ustar, NULL, NULL) == OPKG_OPK_ERROR) { - return OPKG_OPK_ERROR; - } - } - - /* Decompress next (hopefully valid header) record. */ - switch (opkg_opk_gzip_read(ustar->gzip, &ustar->header)) { - case OPKG_OPK_OK: - break; - case OPKG_OPK_END: - /* End of gzip stream before end of ustar archive */ - case OPKG_OPK_ERROR: - return OPKG_OPK_ERROR; - } - - /* Check for end of archive. */ - memset(ustar->record, 0, OPKG_OPK_USTAR_RECORD_SIZE); - if (memcmp(&ustar->header, ustar->record, - OPKG_OPK_USTAR_RECORD_SIZE) == 0) { - return OPKG_OPK_END; - } - - /* Verify magic. */ - if (memcmp(ustar->header.magic, "ustar", strlen("ustar")) != 0) { - return OPKG_OPK_ERROR; - } - - /* Verify checksum. */ - /* Assumes chksum is NUL-terminated. Not required by POSIX, but done by - * GNU and BB tar and opkg_opk_ustar_write_header(). */ - chksum_got = strtol(ustar->header.chksum, &end, - OPKG_OPK_USTAR_NUM_BASE_); - chksum_exp = 0; - if (*end != '\0') { - return OPKG_OPK_ERROR; - } - for (i = 0; i < sizeof(ustar->header.chksum); ++i) { - ustar->header.chksum[i] = ' '; - } - header_uc = (unsigned char *) &ustar->header; - for (i = 0; i < OPKG_OPK_USTAR_RECORD_SIZE; ++i) { - chksum_exp += header_uc[i]; - } - if (chksum_got != chksum_exp) { - return OPKG_OPK_ERROR; - } - - /* Depending on type, get size. */ - switch (*ustar->header.typeflag) { - case '0': /* Regular file */ - case '7': /* High-performance or regular file */ - /* Assumes size is NUL-terminated. Not required by - * POSIX, but done by GNU and BB tar and - * opkg_opk_ustar_write_header(). */ - ustar->data_size_remaining = strtol( - ustar->header.size, &end, - OPKG_OPK_USTAR_NUM_BASE_); - if (*end != '\0') { - return OPKG_OPK_ERROR; - } - break; - case '2': /* Symbolic link */ - case '3': /* Character special file */ - case '4': /* Block special file */ - case '5': /* Directory */ - case '6': /* FIFO special file */ - ustar->data_size_remaining = 0; - break; - case '1': /* Link */ - default: /* Reserved */ - return OPKG_OPK_ERROR; /* Unsupported */ - } - - return OPKG_OPK_OK; -} - -int -opkg_opk_ustar_list(struct opkg_opk_ustar *ustar, - struct opkg_opk_ustar_member **member) -{ - int ret; - char *end; - - /* Get next header record, if any. */ - if ((ret =_opkg_opk_ustar_next(ustar)) != OPKG_OPK_OK) { - return ret; /* Error or end of archive */ - } - - /* Allocate outward-facing member information structure. */ - *member = malloc(sizeof(**member)); - if (*member == NULL) { - return OPKG_OPK_ERROR; - } - - /* Set name, mode, size, mtime, type, linkname, uname, gname, devmajor, - * and devminor. */ - if (ustar->header.prefix[0] != '\0') { - sprintf((*member)->name, "%s/%s", - ustar->header.prefix, ustar->header.name); - } else { - /* Use memcpy() because ustar->header.name may not be - * NUL-terminated. */ - memcpy((*member)->name, ustar->header.name, - sizeof(ustar->header.name)); - (*member)->name[sizeof(ustar->header.name)] = '\0'; - } - /* Assumes mode and mtime are NUL-terminated. Not required by POSIX, - * but done by GNU and BB tar and opkg_opk_ustar_write_header(). */ - (*member)->mode = strtol(ustar->header.mode, &end, - OPKG_OPK_USTAR_NUM_BASE_); - if (*end != '\0') { - free(*member); - return OPKG_OPK_ERROR; - } - (*member)->size = ustar->data_size_remaining; - (*member)->mtime = strtol(ustar->header.mtime, &end, - OPKG_OPK_USTAR_NUM_BASE_); - if (*end != '\0') { - free(*member); - return OPKG_OPK_ERROR; - } - switch (*ustar->header.typeflag) { - case '0': /* Regular file */ - case '7': /* High-performance or regular file */ - (*member)->type = '-'; - break; - case '2': /* Symbolic link */ - (*member)->type = 'l'; - strncpy((*member)->linkname, ustar->header.linkname, - sizeof(ustar->header.linkname)); - (*member)->linkname[sizeof((*member)->linkname) - 1] = - '\0'; - break; - case '3': /* Character special file */ - (*member)->type = 'c'; - break; - case '4': /* Block special file */ - (*member)->type = 'b'; - break; - case '5': /* Directory */ - (*member)->type = 'd'; - break; - case '6': /* FIFO special file */ - (*member)->type = 'p'; - break; - case '1': /* Link */ - default: /* Reserved */ - free(*member); - return OPKG_OPK_ERROR; /* Unsupported */ - } - strncpy((*member)->uname, ustar->header.uname, - sizeof((*member)->uname)); - strncpy((*member)->gname, ustar->header.gname, - sizeof((*member)->gname)); - (*member)->devmajor = strtol(ustar->header.devmajor, &end, - OPKG_OPK_USTAR_NUM_BASE_); - if (*end != '\0') { - free(*member); - return OPKG_OPK_ERROR; - } - (*member)->devminor = strtol(ustar->header.devminor, &end, - OPKG_OPK_USTAR_NUM_BASE_); - if (*end != '\0') { - free(*member); - return OPKG_OPK_ERROR; - } - - return OPKG_OPK_OK; /* Possibly more members in archive */ -} - -int -opkg_opk_ustar_read(struct opkg_opk_ustar *ustar, char **buffer, size_t *size) -{ - if (ustar->data_size_remaining == 0) { - return OPKG_OPK_END; - } - - /* Decompress next data record. */ - switch (opkg_opk_gzip_read(ustar->gzip, ustar->record)) { - case OPKG_OPK_OK: - break; - case OPKG_OPK_END: - case OPKG_OPK_ERROR: - return OPKG_OPK_ERROR; - } - - /* Store buffer and size in caller's memory and update remaining size. - */ - if (buffer != NULL) { - *buffer = ustar->record; - } - if (ustar->data_size_remaining >= OPKG_OPK_USTAR_RECORD_SIZE) { - if (size != NULL) { - *size = OPKG_OPK_USTAR_RECORD_SIZE; - } - ustar->data_size_remaining -= OPKG_OPK_USTAR_RECORD_SIZE; - } else { - if (size != NULL) { - *size = ustar->data_size_remaining; - } - ustar->data_size_remaining = 0; - } - return OPKG_OPK_OK; -} - -int -opkg_opk_ustar_write_header(struct opkg_opk_ustar *ustar, - struct opkg_opk_dirent *dirent, uint16_t mode, - uid_t uid, const char *uname, gid_t gid, const char *gname, - uint32_t devmajor, uint32_t devminor, - uint64_t size, uint64_t mtime, char type, const char *linkname) -{ - uint32_t chksum; - size_t i; - unsigned char *header_uc; - - memset(&ustar->header, 0, sizeof(ustar->header)); - - if (opkg_opk_dirent_name_prefix(dirent, (type == 'd' ? 1 : 0), - ustar->header.name, - sizeof(ustar->header.name), - ustar->header.prefix, - sizeof(ustar->header.prefix)) != OPKG_OPK_OK) { - return OPKG_OPK_ERROR; - } - /* POSIX doesn't say to NUL-terminate mode, uid, gid, size, or mtime. - * GNU and BB tar accept values that aren't (but generate values that - * ARE) NUL-terminated. But more importantly, opkg-lede (see file - * libbb/unarchive.c) parses these with simple strtol() calls, without - * even checking endptr, so we have to NUL-terminate these fields. Also - * parsing these fields with strtol() are our very own - * _opkg_opk_ustar_next() and opkg_opk_ustar_list() above. */ - sprintf(ustar->header.mode, "%07o", mode); - sprintf(ustar->header.uid, "%07o", uid); - sprintf(ustar->header.gid, "%07o", gid); - sprintf(ustar->header.size, "%011o", size); - sprintf(ustar->header.mtime, "%011o", mtime); - sprintf(ustar->header.devmajor, "%07o", devmajor); - sprintf(ustar->header.devminor, "%07o", devminor); - switch (type) { - case '-': /* Regular file */ - *ustar->header.typeflag = '0'; - break; - case 'l': /* Symbolic link */ - *ustar->header.typeflag = '2'; - strncpy(ustar->header.linkname, linkname, - sizeof(ustar->header.linkname)); - break; - case 'c': /* Character special file */ - *ustar->header.typeflag = '3'; - break; - case 'b': /* Block special file */ - *ustar->header.typeflag = '4'; - break; - case 'd': /* Directory */ - *ustar->header.typeflag = '5'; - break; - case 'p': /* FIFO special file */ - *ustar->header.typeflag = '6'; - break; - default: - return OPKG_OPK_ERROR; /* Unsupported */ - } - strncpy(ustar->header.uname, uname, sizeof(ustar->header.uname)); - strncpy(ustar->header.gname, gname, sizeof(ustar->header.gname)); - - /* In these fields POSIX says to write: But GNU and BB tar write: */ - strcpy(ustar->header.magic, "ustar"); /* "ustar " */ - memcpy(ustar->header.version, "00", 2); /* " \0" i.e. 0x20 0x00 */ - /* See files in BusyBox: - * include/bb_archive.h - * archival/chksum_and_xwrite_tar_header.c - * archival/libarchive/get_header_tar.c - * GNU and BB tar accept POSIX-conformant magic and version fields. - * opkg-lede libbb/unarchive.c only checks first 5 bytes of magic and - * ignores version. So conforming to POSIX seems safe. - */ -#if OPKG_OPK_USTAR_BB_EXACT_HEADER_ - strcpy(ustar->header.magic, "ustar "); -#endif - - chksum = 0; - for (i = 0; i < sizeof(ustar->header.chksum); ++i) { - ustar->header.chksum[i] = ' '; - } - header_uc = (unsigned char *) &ustar->header; - for (i = 0; i < OPKG_OPK_USTAR_RECORD_SIZE; ++i) { - chksum += header_uc[i]; - } - /* See above about NUL-terminating and strtol() in opkg-lede. */ - /* Since commit 5661fe078eed752780b11f3f4fdd33bbd76a6c5e, BB tar has - * filled chksum with "[6] digits, a null, then a space -- rather than - * digits, followed by a null like the other fields...". The maxiumum - * checksum is (255 x 512 = octal 377000), i.e. a maximum of 6 octal - * digits, so it doesn't matter whether we use 6 or 7 digits. */ -#if OPKG_OPK_USTAR_BB_EXACT_HEADER_ - sprintf(ustar->header.chksum, "%06o", chksum); -#else - sprintf(ustar->header.chksum, "%07o", chksum); -#endif - - if (opkg_opk_gzip_write(ustar->gzip, &ustar->header, - OPKG_OPK_USTAR_RECORD_SIZE) != OPKG_OPK_OK) { - return OPKG_OPK_ERROR; - } - - ustar->data_size_remaining = size; - return OPKG_OPK_OK; -} - -int -opkg_opk_ustar_get_buffer(struct opkg_opk_ustar *ustar, char **buffer, - size_t *size) -{ - *buffer = ustar->record; - *size = sizeof(ustar->record); - return OPKG_OPK_OK; -} - -int -opkg_opk_ustar_write_data(struct opkg_opk_ustar *ustar, size_t size) -{ - /* Sanity check. */ - if (size > ustar->data_size_remaining || - size > OPKG_OPK_USTAR_RECORD_SIZE) { - return OPKG_OPK_ERROR; - } - - /* Zero out end of record. */ - memset(ustar->record + size, 0, OPKG_OPK_USTAR_RECORD_SIZE - size); - - /* Write to gzip stream. */ - if (opkg_opk_gzip_write(ustar->gzip, ustar->record, - OPKG_OPK_USTAR_RECORD_SIZE) != OPKG_OPK_OK) { - return OPKG_OPK_ERROR; - } - - ustar->data_size_remaining -= size; - return OPKG_OPK_OK; -} - -int -opkg_opk_ustar_write_trailer(struct opkg_opk_ustar *ustar) -{ - memset(ustar->record, 0, OPKG_OPK_USTAR_RECORD_SIZE); - if (opkg_opk_gzip_write(ustar->gzip, ustar->record, - OPKG_OPK_USTAR_RECORD_SIZE) != OPKG_OPK_OK || - opkg_opk_gzip_write(ustar->gzip, ustar->record, - OPKG_OPK_USTAR_RECORD_SIZE) != OPKG_OPK_OK) - { - return OPKG_OPK_ERROR; - } - return OPKG_OPK_OK; -} - -void -opkg_opk_ustar_free(struct opkg_opk_ustar *ustar) -{ - free(ustar); -} diff --git a/src/ustar.h b/src/ustar.h deleted file mode 100644 index 4a3dc1a..0000000 --- a/src/ustar.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2023 Patrick McDermott - * - * This file is part of opkg-opk. - * - * opkg-opk 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-opk 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-opk. If not, see <https://www.gnu.org/licenses/>. - */ - -#ifndef OPKG_OPK_USTAR_H_ -#define OPKG_OPK_USTAR_H_ - -#include <stdint.h> -#include "dirent.h" -#include "gzip.h" - -#define OPKG_OPK_USTAR_RECORD_SIZE 512 -#define OPKG_OPK_USTAR_NAME_SIZE 257 /* prefix[155] + '/' + name[100] - + '\0' */ -#define OPKG_OPK_USTAR_LINKNAME_SIZE 101 /* linkname[100] + '\0' */ - -struct opkg_opk_ustar; - -struct opkg_opk_ustar_member { - char name [OPKG_OPK_USTAR_NAME_SIZE]; - uint16_t mode; - uint64_t size; - uint64_t mtime; - char type; - char linkname[OPKG_OPK_USTAR_LINKNAME_SIZE]; - char uname [32]; - char gname [32]; - uint32_t devmajor; - uint32_t devminor; - struct opkg_opk_ustar_member *next; -}; - -struct opkg_opk_ustar_seek_name; - -/* - * Allocates and initializes an archive structure. - * Parameters: - * - gzip: Decompressor for archive's gzip stream. - * Returns: - * - Allocated archive structure on success. Free with opkg_opk_ustar_free(). - * - NULL on memory exhaustion. - */ -struct opkg_opk_ustar * -opkg_opk_ustar_init(struct opkg_opk_gzip *gzip); - -/* - * Lists member files one at a time. - * Parameters: - * - ustar: Archive structure. - * - member: Address in which to store address of allocated member structure. - * Free with free(). - * Returns: - * - OPKG_OPK_OK if a member was listed. More members may exist. - * - OPKG_OPK_END if no more members exist. Parameter "member" is unchanged. - * - OPKG_OPK_ERROR on decompression error, memory exhaustion, mode or mtime - * integer conversion error, or unsupported file type. - */ -int -opkg_opk_ustar_list(struct opkg_opk_ustar *ustar, - struct opkg_opk_ustar_member **member); - -/* - * Reads up to a record (512 octets) of member file data at a time. - * Parameters: - * - ustar: Archive structure. - * - buffer: Address in which to store address of data buffer. May be NULL. Do - * not free. - * - size: Address in which to store size of read data. May be NULL. - * Returns: - * - OPKG_OPK_OK if data was read. - * - OPKG_OPK_END if no more data exists. - * - OPKG_OPK_ERROR on decompression error or premature end of gzip stream. - */ -int -opkg_opk_ustar_read(struct opkg_opk_ustar *ustar, char **buffer, size_t *size); - -int -opkg_opk_ustar_write_header(struct opkg_opk_ustar *ustar, - struct opkg_opk_dirent *dirent, uint16_t mode, - uid_t uid, const char *uname, gid_t gid, const char *gname, - uint32_t devmajor, uint32_t devminor, - uint64_t size, uint64_t mtime, char type, const char *linkname); - -int -opkg_opk_ustar_get_buffer(struct opkg_opk_ustar *ustar, char **buffer, - size_t *size); - -int -opkg_opk_ustar_write_data(struct opkg_opk_ustar *ustar, size_t size); - -int -opkg_opk_ustar_write_trailer(struct opkg_opk_ustar *ustar); - -/* - * Frees an archive structure. - * Parameters: - * - ustar: Archive structure. - */ -void -opkg_opk_ustar_free(struct opkg_opk_ustar *ustar); - -#endif /* OPKG_OPK_USTAR_H_ */ |