From 00693f2324318f196cab57823526d3133fa7a146 Mon Sep 17 00:00:00 2001 From: Patrick McDermott Date: Tue, 25 Apr 2023 15:11:24 -0400 Subject: gzip: Add write direction --- (limited to 'src') diff --git a/src/gzip.c b/src/gzip.c index a53be83..2717f54 100644 --- a/src/gzip.c +++ b/src/gzip.c @@ -25,43 +25,104 @@ #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 { - int (*read)(void *, char **, size_t *); - void *user_data; - z_stream stream; + enum _opkg_opk_gzip_dir dir; + char *buffer; + size_t buffer_size; + opkg_opk_gzip_read_func *read_func; + opkg_opk_gzip_write_func *write_func; + void *user_data; + z_stream stream; }; -struct opkg_opk_gzip * -opkg_opk_gzip_init(opkg_opk_gzip_read_func *read, void *user_data) +static struct opkg_opk_gzip * +_opkg_opk_gzip_init(enum _opkg_opk_gzip_dir dir, char *buffer, size_t size, + opkg_opk_gzip_read_func *read_func, + opkg_opk_gzip_write_func *write_func, void *user_data) { struct opkg_opk_gzip *gzip; + gz_header gz_header; gzip = malloc(sizeof(*gzip)); if (gzip == NULL) { return NULL; } - gzip->read = read; - gzip->user_data = user_data; + gzip->dir = dir; + gzip->buffer = buffer; + gzip->buffer_size = size; + gzip->read_func = read_func; + gzip->write_func = write_func; + gzip->user_data = user_data; - gzip->stream.next_in = Z_NULL; - gzip->stream.avail_in = 0; gzip->stream.zalloc = Z_NULL; gzip->stream.zfree = Z_NULL; gzip->stream.opaque = Z_NULL; - if (inflateInit2(&gzip->stream, OPKG_OPK_GZIP_WINDOW_BITS_) != Z_OK) { - free(gzip); - return NULL; + + if (dir == _OPKG_OPK_GZIP_DIR_READ) { + 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; + } + } else { + gzip->stream.next_out = buffer; + gzip->stream.avail_out = size; + if (deflateInit2(&gzip->stream, 9, Z_DEFLATED, + OPKG_OPK_GZIP_WINDOW_BITS_, 9, + Z_DEFAULT_STRATEGY) != Z_OK) { + free(gzip); + return NULL; + } + gz_header.text = 0; + gz_header.time = 0; /* Stored as 32-bit unsigned int */ + gz_header.os = 3; /* Unix, per RFC 1952 */ + gz_header.extra = Z_NULL; + gz_header.name = Z_NULL; + gz_header.comment = Z_NULL; + gz_header.hcrc = 0; + if (deflateSetHeader(&gzip->stream, &gz_header) != Z_OK) { + deflateEnd(&gzip->stream); + free(gzip); + return NULL; + } } return gzip; } +struct opkg_opk_gzip * +opkg_opk_gzip_init_read(opkg_opk_gzip_read_func *read, void *user_data) +{ + return _opkg_opk_gzip_init(_OPKG_OPK_GZIP_DIR_READ, NULL, 0, + read, NULL, user_data); +} + +struct opkg_opk_gzip * +opkg_opk_gzip_init_write(char *buffer, size_t size, + opkg_opk_gzip_write_func *write, void *user_data) +{ + return _opkg_opk_gzip_init(_OPKG_OPK_GZIP_DIR_WRITE, buffer, size, + NULL, write, user_data); +} + 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; @@ -69,7 +130,7 @@ opkg_opk_gzip_read(struct opkg_opk_gzip *gzip, void *record) end = 0; if (gzip->stream.avail_in == 0) { /* Input buffer is empty and needs refilled. */ - switch (gzip->read(gzip->user_data, + switch (gzip->read_func(gzip->user_data, (char **) &gzip->stream.next_in, (size_t *) &gzip->stream. avail_in)) { @@ -107,9 +168,69 @@ opkg_opk_gzip_read(struct opkg_opk_gzip *gzip, void *record) } } -void +int +opkg_opk_gzip_write(struct opkg_opk_gzip *gzip, void *record, size_t size, + int last) +{ + /* 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 { + 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. */ + switch (gzip->write_func(gzip->user_data, + gzip->buffer_size + - gzip->stream.avail_out)) { + case OPKG_OPK_OK: + gzip->stream.next_out = gzip->buffer; + gzip->stream.avail_out = gzip->buffer_size; + break; + case OPKG_OPK_END: + case OPKG_OPK_ERROR: + default: + return OPKG_OPK_ERROR; + } + } 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_free(struct opkg_opk_gzip *gzip) { - inflateEnd(&gzip->stream); + 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 index e4c3f52..1fd5d5e 100644 --- a/src/gzip.h +++ b/src/gzip.h @@ -23,6 +23,7 @@ struct opkg_opk_gzip; typedef int (opkg_opk_gzip_read_func)(void *, char **, size_t *); +typedef int (opkg_opk_gzip_write_func)(void *, size_t); /* * Allocates and initializes a decompression structure. @@ -41,7 +42,11 @@ typedef int (opkg_opk_gzip_read_func)(void *, char **, size_t *); * - NULL on memory exhaustion. */ struct opkg_opk_gzip * -opkg_opk_gzip_init(opkg_opk_gzip_read_func *read, void *user_data); +opkg_opk_gzip_init_read(opkg_opk_gzip_read_func *read, void *user_data); + +struct opkg_opk_gzip * +opkg_opk_gzip_init_write(char *buffer, size_t size, + opkg_opk_gzip_write_func *write, void *user_data); /* * Reads and decompresses data to output the next record (512 octets). @@ -57,12 +62,16 @@ opkg_opk_gzip_init(opkg_opk_gzip_read_func *read, void *user_data); 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, + int last); + /* * Frees a decompression structure. * Parameters: * - gzip: Decompression structure. */ -void +int opkg_opk_gzip_free(struct opkg_opk_gzip *gzip); #endif /* OPKG_OPK_GZIP_H_ */ diff --git a/src/opk.c b/src/opk.c index 2747345..982ad3f 100644 --- a/src/opk.c +++ b/src/opk.c @@ -76,7 +76,8 @@ opkg_opk_opk_init(const char *file_name) } /* Initialize outer gzip decompressor. */ - opk->outer_gzip = opkg_opk_gzip_init(&_opkg_opk_opk_file_read, opk); + opk->outer_gzip = opkg_opk_gzip_init_read(&_opkg_opk_opk_file_read, + opk); if (opk->outer_gzip == NULL) { fputs(_("Error: Failed to initialize\n"), stderr); goto error2; @@ -146,7 +147,7 @@ _opkg_opk_opk_init_inner(struct opkg_opk_opk *opk, const char *member) } /* Initialize inner gzip decompressor. */ - opk->inner_gzip = opkg_opk_gzip_init( + 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) { -- cgit v0.9.1