summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gzip.c151
-rw-r--r--src/gzip.h13
-rw-r--r--src/opk.c5
3 files changed, 150 insertions, 19 deletions
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) {