diff options
Diffstat (limited to '')
-rw-r--r-- | kexec/zlib.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/kexec/zlib.c b/kexec/zlib.c new file mode 100644 index 0000000..3ed6bd6 --- /dev/null +++ b/kexec/zlib.c @@ -0,0 +1,129 @@ +#include "kexec-zlib.h" +#include "kexec.h" + +#ifdef HAVE_LIBZ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <ctype.h> +#include <zlib.h> + +static void _gzerror(gzFile fp, int *errnum, const char **errmsg) +{ + *errmsg = gzerror(fp, errnum); + if (*errnum == Z_ERRNO) { + *errmsg = strerror(*errnum); + } +} + +int is_zlib_file(const char *filename, off_t *r_size) +{ + gzFile fp; + int errnum; + int is_zlib_file = 0; /* default: It's not in gzip format */ + const char *msg; + ssize_t result; + + if (!filename) + goto out; + + fp = gzopen(filename, "rb"); + if (fp == 0) { + _gzerror(fp, &errnum, &msg); + dbgprintf("Cannot open `%s': %s\n", filename, msg); + goto out; + } + + if (!gzdirect(fp)) + /* It's in gzip format */ + is_zlib_file = 1; + + result = gzclose(fp); + if (result != Z_OK) { + _gzerror(fp, &errnum, &msg); + dbgprintf(" Close of %s failed: %s\n", filename, msg); + } + +out: + return is_zlib_file; +} + +char *zlib_decompress_file(const char *filename, off_t *r_size) +{ + gzFile fp; + int errnum; + const char *msg; + char *buf = NULL; + off_t size = 0, allocated; + ssize_t result; + + dbgprintf("Try gzip decompression.\n"); + + *r_size = 0; + if (!filename) { + return NULL; + } + fp = gzopen(filename, "rb"); + if (fp == 0) { + _gzerror(fp, &errnum, &msg); + dbgprintf("Cannot open `%s': %s\n", filename, msg); + return NULL; + } + if (gzdirect(fp)) { + /* It's not in gzip format */ + goto fail; + } + allocated = 65536; + buf = xmalloc(allocated); + do { + if (size == allocated) { + allocated <<= 1; + buf = xrealloc(buf, allocated); + } + result = gzread(fp, buf + size, allocated - size); + if (result < 0) { + if ((errno == EINTR) || (errno == EAGAIN)) + continue; + _gzerror(fp, &errnum, &msg); + dbgprintf("Read on %s of %d bytes failed: %s\n", + filename, (int)(allocated - size), msg); + size = 0; + goto fail; + } + size += result; + } while(result > 0); + +fail: + result = gzclose(fp); + if (result != Z_OK) { + _gzerror(fp, &errnum, &msg); + dbgprintf(" Close of %s failed: %s\n", filename, msg); + } + + if (size > 0) { + *r_size = size; + } else { + free(buf); + buf = NULL; + } + return buf; +} +#else + +int is_zlib_file(const char *filename, off_t *r_size) +{ + return 0; +} + +char *zlib_decompress_file(const char *UNUSED(filename), off_t *UNUSED(r_size)) +{ + return NULL; +} +#endif /* HAVE_ZLIB */ |