diff options
author | Patrick McDermott <patrick.mcdermott@libiquity.com> | 2023-04-18 16:41:42 (EDT) |
---|---|---|
committer | Patrick McDermott <patrick.mcdermott@libiquity.com> | 2023-04-18 19:47:12 (EDT) |
commit | b65c075d13990383f30b27aeafacdd4575fafdee (patch) | |
tree | c338c3db137405b98bf74091d9c9965d5c92d7cf | |
parent | 25ce512c39f578def257f81e10e22b06123a069d (diff) |
ustar: Use linked list instead of varargs in seek
Also indicate when all sought member files are found.
-rw-r--r-- | src/main.c | 19 | ||||
-rw-r--r-- | src/opk.c | 25 | ||||
-rw-r--r-- | src/opk.h | 5 | ||||
-rw-r--r-- | src/ustar.c | 74 | ||||
-rw-r--r-- | src/ustar.h | 39 |
5 files changed, 131 insertions, 31 deletions
@@ -20,11 +20,21 @@ #include <stdlib.h> #include "defs.h" #include "opk.h" +#include "ustar.h" int main(int argc, char *argv[]) { - struct opkg_opk_opk *opk; + struct opkg_opk_ustar_seek_name *control_files_head; + struct opkg_opk_ustar_seek_name *control_files_tail; + struct opkg_opk_opk *opk; + + control_files_head = control_files_tail = NULL; + if (opkg_opk_ustar_add_seek_name( + &control_files_head, &control_files_tail, + "control") != OPKG_OPK_OK) { + goto error0; + } /* Initialize outer archive. */ opk = opkg_opk_opk_init_outer(argv[1]); @@ -36,7 +46,7 @@ main(int argc, char *argv[]) if (opkg_opk_opk_init_inner(opk, "control.tar.gz") != OPKG_OPK_OK) { goto error1; } - if (opkg_opk_opk_read_control(opk) != OPKG_OPK_OK) { + if (opkg_opk_opk_read_control(opk, control_files_head) != OPKG_OPK_OK) { goto error2; } opkg_opk_opk_free_inner(opk); @@ -58,5 +68,10 @@ main(int argc, char *argv[]) error1: opkg_opk_opk_free_outer(opk); error0: + for (control_files_tail = control_files_head; + control_files_tail != NULL; ) { + control_files_tail = control_files_head->next; + free(control_files_head); + } return EXIT_FAILURE; } @@ -59,7 +59,8 @@ _opkg_opk_opk_file_read(void *user_data, char **buffer, size_t *size) struct opkg_opk_opk * opkg_opk_opk_init_outer(const char *file_name) { - struct opkg_opk_opk *opk; + struct opkg_opk_opk *opk; + struct opkg_opk_ustar_seek_name seek_name; opk = malloc(sizeof(*opk)); if (opk == NULL) { @@ -89,8 +90,10 @@ opkg_opk_opk_init_outer(const char *file_name) } /* Check package version. */ - if (opkg_opk_ustar_seek(opk->outer_ustar, 1, "debian-binary") != - OPKG_OPK_OK) { + seek_name.name = "debian-binary"; + seek_name.next = NULL; + if (opkg_opk_ustar_seek(opk->outer_ustar, &seek_name) == OPKG_OPK_ERROR) + { fputs("Error: Failed to find \"debian-binary\" in archive\n", stderr); goto error3; @@ -125,7 +128,8 @@ opkg_opk_opk_init_outer(const char *file_name) int opkg_opk_opk_init_inner(struct opkg_opk_opk *opk, const char *member) { - int ret; + int ret; + struct opkg_opk_ustar_seek_name seek_name; /* Finish reading previous inner archive, if any. */ while ((ret = opkg_opk_ustar_read(opk->outer_ustar, NULL, NULL)) == @@ -136,8 +140,11 @@ opkg_opk_opk_init_inner(struct opkg_opk_opk *opk, const char *member) } /* Find requested inner archive. */ - if (opkg_opk_ustar_seek(opk->outer_ustar, 1, member) != - OPKG_OPK_OK) { + seek_name.name = member; + seek_name.found = 0; + seek_name.next = NULL; + if (opkg_opk_ustar_seek(opk->outer_ustar, &seek_name) == OPKG_OPK_ERROR) + { fprintf(stderr, "Error: Failed to find \"%s\" in archive\n", member); return OPKG_OPK_ERROR; @@ -164,7 +171,8 @@ opkg_opk_opk_init_inner(struct opkg_opk_opk *opk, const char *member) } int -opkg_opk_opk_read_control(struct opkg_opk_opk *opk) +opkg_opk_opk_read_control(struct opkg_opk_opk *opk, + struct opkg_opk_ustar_seek_name *names) { char *buffer; size_t size; @@ -174,8 +182,7 @@ opkg_opk_opk_read_control(struct opkg_opk_opk *opk) puts(""); } - if (opkg_opk_ustar_seek(opk->inner_ustar, 2, "control", "./control") != - OPKG_OPK_OK) { + if (opkg_opk_ustar_seek(opk->inner_ustar, names) == OPKG_OPK_ERROR) { fputs("Error: Failed to find control file\n", stderr); return OPKG_OPK_ERROR; } @@ -20,6 +20,8 @@ #ifndef OPKG_OPK_OPK_H_ #define OPKG_OPK_OPK_H_ +#include "ustar.h" + struct opkg_opk_opk; struct opkg_opk_opk * @@ -29,7 +31,8 @@ int opkg_opk_opk_init_inner(struct opkg_opk_opk *opk, const char *member); int -opkg_opk_opk_read_control(struct opkg_opk_opk *opk); +opkg_opk_opk_read_control(struct opkg_opk_opk *opk, + struct opkg_opk_ustar_seek_name *names); int opkg_opk_opk_list_members(struct opkg_opk_opk *opk); diff --git a/src/ustar.c b/src/ustar.c index cf1134a..2a386f0 100644 --- a/src/ustar.c +++ b/src/ustar.c @@ -17,7 +17,6 @@ * along with opkg-opk. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdarg.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -227,13 +226,38 @@ opkg_opk_ustar_list(struct opkg_opk_ustar *ustar, } int -opkg_opk_ustar_seek(struct opkg_opk_ustar *ustar, int num_keys, ...) +opkg_opk_ustar_add_seek_name(struct opkg_opk_ustar_seek_name **head, + struct opkg_opk_ustar_seek_name **tail, const char *name) { - static struct _opkg_opk_ustar_header header; - static char name[OPKG_OPK_USTAR_NAME_MAX_LEN]; - va_list ap; - int key; - const char *member; + struct opkg_opk_ustar_seek_name *seek_name; + + seek_name = malloc(sizeof(*seek_name)); + if (seek_name == NULL) { + return OPKG_OPK_ERROR; + } + seek_name->name = name; + seek_name->found = 0; + seek_name->next = NULL; + + if (*head == NULL) { + *head = seek_name; + } else { + (*tail)->next = seek_name; + } + *tail = seek_name; + + return OPKG_OPK_OK; +} + +int +opkg_opk_ustar_seek(struct opkg_opk_ustar *ustar, + struct opkg_opk_ustar_seek_name *names) +{ + static struct _opkg_opk_ustar_header header; + static char name[OPKG_OPK_USTAR_NAME_MAX_LEN]; + int found; + int found_all; + struct opkg_opk_ustar_seek_name *seek_name; for (;;) { /* Get next header record. */ @@ -251,14 +275,38 @@ opkg_opk_ustar_seek(struct opkg_opk_ustar *ustar, int num_keys, ...) } /* Check each requested name. */ - va_start(ap, num_keys); - for (key = 0; key < num_keys; ++key) { - member = va_arg(ap, const char *); - if (strcmp(name, member) == 0) { - return OPKG_OPK_OK; /* Member found */ + found = 0; + found_all = 1; + for (seek_name = names; seek_name != NULL; + seek_name = seek_name->next) { + if (seek_name->found == 1) { + continue; /* Previously found this member */ + } + if (strcmp(name, seek_name->name) == 0) { + if (found == 0) { + seek_name->found = 1; + found = 1; + continue; + } + } + if (name[0] == '.' && name[1] == '/' && + strcmp(name + 2, seek_name->name) == 0) + { + if (found == 0) { + seek_name->found = 1; + found = 1; + continue; + } + } + found_all = 0; + } + if (found == 1) { + if (found_all == 1) { + /* All requested members found */ + return OPKG_OPK_END; } + return OPKG_OPK_OK; /* Member found, but more remain */ } - va_end(ap); /* Seek through data records until next header record. */ while (ustar->data_size_remaining > 0) { diff --git a/src/ustar.h b/src/ustar.h index 47f3efa..d2317b6 100644 --- a/src/ustar.h +++ b/src/ustar.h @@ -21,6 +21,7 @@ #define OPKG_OPK_USTAR_H_ #include <stdint.h> +#include "gzip.h" #define OPKG_OPK_USTAR_RECORD_SIZE 512 #define OPKG_OPK_USTAR_NAME_MAX_LEN 257 /* prefix[155] + '/' + name[100] + '\0' @@ -40,6 +41,12 @@ struct opkg_opk_ustar_member { struct opkg_opk_ustar_member *next; }; +struct opkg_opk_ustar_seek_name { + const char *name; + int found; + struct opkg_opk_ustar_seek_name *next; +}; + /* * Allocates and initializes an archive structure. * Parameters: @@ -68,18 +75,38 @@ opkg_opk_ustar_list(struct opkg_opk_ustar *ustar, struct opkg_opk_ustar_member **member); /* - * Advances to a named member file. + * Adds a name to a list of names to find with opkg_opk_ustar_seek(). List is + * dynamically allocated; free with free(). * Parameters: - * - ustar: Archive structure. - * - num_keys: Number of search keys to follow. - * - ...: Search keys of type (const char *). + * - head: Address in which to store address of list head. + * - tail: Address in which to store address of list tail. + * - name: Name of member file to find. + * Returns: + * - OPKG_OPK_OK if the name was added to the list. + * - OPKG_OPK_ERROR on memory exhaustion. + */ +int +opkg_opk_ustar_add_seek_name(struct opkg_opk_ustar_seek_name **head, + struct opkg_opk_ustar_seek_name **tail, const char *name); + +/* + * Advances to a named member file. May be called multiple times until all + * requested members are found. + * Parameters: + * - ustar: Archive structure. + * - names: Name(s) to find. Member "found" will be set to "1" on the first + * name found. * Returns: - * - OPKG_OPK_OK if a member matching one of the search keys is found. + * - OPKG_OPK_OK if a member matching one of the requested names is found but + * more names remain to be found. + * - OPKG_OPK_END if a member matching one of the requested names is found and + * no more names remain to be found. * - OPKG_OPK_ERROR if no matching member is found or on decompression error, an * invalid header, or unsupported file type. */ int -opkg_opk_ustar_seek(struct opkg_opk_ustar *ustar, int num_keys, ...); +opkg_opk_ustar_seek(struct opkg_opk_ustar *ustar, + struct opkg_opk_ustar_seek_name *names); /* * Reads up to a record (512 octets) of member file data at a time. |