summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile12
-rw-r--r--fzopen.3.in15
-rw-r--r--zio.c417
-rw-r--r--zio.h.in3
-rw-r--r--zioP.h22
5 files changed, 461 insertions, 8 deletions
diff --git a/Makefile b/Makefile
index f8f8c43..b4a8a45 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ LARGE = $(shell getconf LFS_CFLAGS)
CFLAGS = $(RPM_OPT_FLAGS) -pipe -Wall -D_GNU_SOURCE -D_REENTRANT -D_DEFAULT_SOURCE $(LARGE)
CC = gcc
MAJOR = 1
-MINOR = 06
+MINOR = 08
VERSION = $(MAJOR).$(MINOR)
SONAME = libzio.so.$(MAJOR)
LDMAP = -Wl,--version-script=zio.map
@@ -47,6 +47,7 @@ CFLAGS += $(call cc-include,zlib.h,HAS_ZLIB_H)
CFLAGS += $(call cc-include,bzlib.h,HAS_BZLIB_H)
CFLAGS += $(call cc-include,lzmadec.h,HAS_LZMADEC_H)
CFLAGS += $(call cc-include,lzma.h,HAS_LZMA_H)
+CFLAGS += $(call cc-include,zstd.h,HAS_ZSTD_H)
LIBS = -lz
ifeq ($(call cc-library,libbz2),yes)
@@ -59,6 +60,9 @@ ifeq ($(call cc-library,lzmadec),yes)
LIBS += -llzmadec
endif
endif
+ifeq ($(call cc-library,libzstd),yes)
+ LIBS += -lzstd
+endif
all: shared static
noweak: CFLAGS += -DNO_WEAK
@@ -117,14 +121,14 @@ install-data: zio.h fzopen.3
install -m 0644 fzopen.3 $(DESTDIR)$(mandir)/man3/
clean:
- rm -f *.a *.so* testt tests zio.h
+ rm -f *.a *.so* testt tests testx zio.h
rm -rf obj/ obs/
- rm -f libzio-$(VERSION).tar.gz
+ rm -f libzio-$(VERSION).tar.bz2
dest: clean
mkdir libzio-$(VERSION)
cp -p $(FILES) libzio-$(VERSION)/
- tar czf libzio-$(VERSION).tar.gz libzio-$(VERSION)/
+ tar czf libzio-$(VERSION).tar.bz2 libzio-$(VERSION)/
rm -rf libzio-$(VERSION)/
testt: testt.c libzio.a
diff --git a/fzopen.3.in b/fzopen.3.in
index b4d8357..1b226a6 100644
--- a/fzopen.3.in
+++ b/fzopen.3.in
@@ -69,6 +69,9 @@ The file descriptor points to a lzma2ed file.
.TP
.BR Z
The file descriptor points to a file in LZW format.
+.TP
+.BR s
+The file descriptor points to a file in zst format.
.PP
Note that
.B fzopen
@@ -116,6 +119,7 @@ bzip2 yes yes yes .bz2 -lbz2
LZW yes no yes .Z builtin
lzma yes yes(no) yes .lzma -llzma (-llzmadec)
xz yes yes yes .xz -llzma
+zstd yes yes no .zst -lzstd
.TE
.PP
.PP
@@ -184,6 +188,15 @@ if test "$am_cv_libzio" = yes; then
])
done
])
+ AC_CHECK_HEADER(zstd.h, [
+ for lib in lzstd; do
+ AC_CHECK_LIB($lib, ZSTD_createCStream, [
+ LIBS="$LIBS -l$lib"
+ am_cv_libzio="$am_cv_libzio lib$lib"
+ break
+ ])
+ done
+ ])
AC_MSG_NOTICE([libzio is used [$]am_cv_libzio])
fi
.fi
@@ -347,5 +360,7 @@ functions of the e.g.
.br
2006,2008,2009 Werner Fink,
2006,2008,2009 SuSE Products GmbH, Germany.
+.br
+2021 Werner Fink, 2021 SUSE Software Solutions Germany GmbH, Germany.
.SH AUTHOR
Werner Fink <werner@suse.de>
diff --git a/zio.c b/zio.c
index be27da5..f50d873 100644
--- a/zio.c
+++ b/zio.c
@@ -1,11 +1,12 @@
/*
- * zio.c Provide an streamable interface to gziped/bzip2ed/LZW/LZMA files
+ * zio.c Provide an streamable interface to gziped/bzip2ed/LZW/LZMA/zst files
*
* Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
* Copyright 2006 Werner Fink, 2006 SuSE Products GmbH, Germany.
* Copyright 2009 Werner Fink, 2009 SuSE Products GmbH, Germany.
* Copyright 2013 Werner Fink, 2013 SuSE Products GmbH, Germany.
* Copyright 2017 Werner Fink, 2017 SUSE Linux GmbH, Germany.
+ * Copyright 2021 Werner Fink, 2021 SUSE Software Solutions Germany GmbH, Germany.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -526,6 +527,261 @@ static cookie_io_functions_t iolzma = {
# endif /* !HAS_LZMADEC_H */
#endif /* !HAS_LZMA_H */
+#if defined(HAS_ZSTD_H)
+
+#ifndef MIN
+# define MIN(x,y) ((x) < (y) ? (x) : (y))
+#endif
+
+typedef struct zstdfile_s {
+ ZSTD_CStream* cstream;
+ ZSTD_DStream* dstream;
+ ZSTD_inBuffer in;
+ ZSTD_outBuffer out;
+ void *buf_in, *buf_out;
+ size_t init;
+ size_t insize;
+#if 0
+ size_t prevwrite;
+#endif
+ FILE *file;
+ FILE *stdio;
+ int level;
+} zstdfile_t;
+
+static int zstdopen(void *cookie)
+{
+ int ret = -1;
+
+ zstdfile_t *zstd = (zstdfile_t*)cookie;
+ if (zstd->cstream) {
+ zstd->init = ZSTD_initCStream(zstd->cstream, zstd->level);
+ if (ZSTD_isError(zstd->init)) {
+ fprintf(stderr, "ZSTD_initCStream error: %s\n", ZSTD_getErrorName(zstd->init));
+ goto out;
+ }
+ zstd->in.size = ZSTD_CStreamInSize();
+ zstd->out.size = ZSTD_CStreamOutSize();
+ zstd->buf_in = malloc(zstd->in.size);
+ if (!zstd->buf_in)
+ goto out;
+ zstd->in.src = zstd->buf_in;
+ zstd->buf_out = malloc(zstd->out.size);
+ if (!zstd->buf_out) {
+ free(zstd->buf_in);
+ goto out;
+ }
+ zstd->out.dst = zstd->buf_out;
+ zstd->in.pos = zstd->out.pos = 0;
+ zstd->insize = zstd->in.size;
+#if 0
+ zstd->prevwrite = 0;
+#endif
+ ret = 0;
+ } else if (zstd->dstream) {
+ zstd->init = ZSTD_initDStream(zstd->dstream);
+ if (ZSTD_isError(zstd->init)) {
+ fprintf(stderr, "ZSTD_initDStream error: %s\n", ZSTD_getErrorName(zstd->init));
+ goto out;
+ }
+ zstd->in.size = ZSTD_DStreamInSize();
+ zstd->out.size = ZSTD_DStreamOutSize();
+ zstd->buf_in = malloc(zstd->in.size);
+ if (!zstd->buf_in)
+ goto out;
+ zstd->in.src = zstd->buf_in;
+ zstd->buf_out = malloc(zstd->out.size);
+ if (!zstd->buf_out) {
+ free(zstd->buf_in);
+ goto out;
+ }
+ zstd->out.dst = zstd->buf_out;
+ zstd->in.pos = zstd->out.pos = 0;
+ zstd->insize = zstd->in.size;
+ ret = 0;
+ }
+out:
+ return ret;
+}
+
+static ssize_t zstdread(void *cookie, char *buf, size_t count)
+{
+ ssize_t ret = -1;
+ zstdfile_t *zstd = (zstdfile_t*)cookie;
+ size_t rlen, rtodo;
+
+ if (zstd->cstream || !zstd->dstream) {
+ errno = ENOTSUP;
+ goto out;
+ }
+
+ ret = 0;
+ if (zstd->out.pos > 0) {
+ rlen = zstd->out.pos;
+ if (rlen > count)
+ rlen = count;
+ memcpy(buf, zstd->out.dst, rlen); /* Copy into stdio buffer ... */
+ zstd->out.dst += rlen;
+ zstd->out.pos -= rlen;
+ ret = rlen;
+ goto out; /* ... and escape here */
+ }
+ zstd->out.dst = zstd->buf_out;
+ zstd->out.pos = 0;
+
+ rtodo = zstd->init;
+ while ((rlen = fread(zstd->buf_in, 1, rtodo, zstd->file))) {
+ zstd->in.src = zstd->buf_in;
+ zstd->in.size = rlen;
+ zstd->in.pos = 0;
+
+ while (zstd->in.pos < zstd->in.size) {
+
+ rtodo = ZSTD_decompressStream(zstd->dstream, &zstd->out, &zstd->in);
+ if (ZSTD_isError(rtodo)) {
+ fprintf(stderr, "ZSTD_decompressStream error: %s\n", ZSTD_getErrorName(rtodo));
+ ret = -1;
+ goto out;
+ }
+
+ if (zstd->out.pos > 0) {
+ rlen = zstd->out.pos;
+ if (rlen > count)
+ rlen = count;
+ memcpy(buf, zstd->out.dst, rlen); /* Copy into stdio buffer ... */
+ zstd->out.dst += rlen;
+ zstd->out.pos -= rlen;
+ ret = rlen;
+ goto out; /* ... and escape here */
+ }
+
+ zstd->out.dst = zstd->buf_out;
+ zstd->out.pos = 0;
+
+ if (rtodo == 0) {
+ zstd->init = ZSTD_initDStream(zstd->dstream);
+ if (ZSTD_isError(zstd->init)) {
+ fprintf(stderr, "ZSTD_decompressStream error: %s\n", ZSTD_getErrorName(rtodo));
+ ret = -1;
+ goto out;
+ }
+ rtodo = zstd->init;
+ ret = 0;
+ }
+ }
+ }
+out:
+ return ret;
+}
+
+static ssize_t zstdwrite(void *cookie, const char *buf, size_t count)
+{
+ ssize_t ret = -1;
+ zstdfile_t *zstd = (zstdfile_t*)cookie;
+ size_t wlen, wtodo;
+ void *src;
+
+#if 0
+ if (zstd->prevwrite == 0)
+ zstd->prevwrite = count;
+#endif
+
+ ret = 0;
+ src = zstd->buf_in+zstd->in.pos;
+ if (zstd->in.pos < zstd->insize) {
+ wlen = zstd->insize - zstd->in.pos;
+ if (wlen > count)
+ wlen = count;
+ memcpy(src, buf, wlen); /* Copy from stdio buffer ... */
+ src += wlen;
+ zstd->in.pos += wlen;
+ ret = wlen;
+ }
+
+#if 0
+ fprintf(stderr, "Harry %lu %lu %lu %lu\n", zstd->prevwrite, count, zstd->in.pos, zstd->insize);
+ if (zstd->prevwrite == count && zstd->in.pos < zstd->insize)
+ goto out; /* ... and ask for more here */
+#endif
+
+ zstd->in.src = zstd->buf_in;
+ zstd->in.size = zstd->in.pos;
+ zstd->in.pos = 0;
+
+ while (zstd->in.pos < zstd->in.size) {
+
+ wtodo = ZSTD_compressStream(zstd->cstream, &zstd->out, &zstd->in);
+ if (ZSTD_isError(wtodo)) {
+ fprintf(stderr, "ZSTD_compressStream error: %s\n", ZSTD_getErrorName(wtodo));
+ ret = -1;
+ goto out;
+ }
+
+ while (zstd->out.pos > 0) {
+ wlen = fwrite(zstd->out.dst, 1, zstd->out.pos, zstd->file);
+ if (wlen == zstd->out.pos || wlen == 0)
+ break;
+ zstd->out.dst += wlen;
+ zstd->out.pos -= wlen;
+ }
+ zstd->out.dst = zstd->buf_out;
+ zstd->out.pos = 0;
+ }
+ zstd->in.pos = 0;
+out:
+ return ret;
+}
+
+static zio_int_t zstdseek(void *cookie, zio_off_t *poffset, int whence)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static int zstdclose(void *cookie)
+{
+ zstdfile_t *zstd = (zstdfile_t*)cookie;
+ int fret;
+ if (zstd->cstream) {
+ size_t wlen, end_res;
+ do {
+ zstd->out.dst = zstd->buf_out;
+ zstd->out.pos = 0;
+ end_res = ZSTD_endStream(zstd->cstream, &zstd->out);
+ if (ZSTD_isError(end_res))
+ fprintf(stderr, "ZSTD_endStream error: %s\n", ZSTD_getErrorName(end_res));
+ while (zstd->out.pos > 0) {
+ wlen = fwrite(zstd->out.dst, 1, zstd->out.pos, zstd->file);
+ if (wlen == zstd->out.pos || wlen == 0)
+ break;
+ zstd->out.dst += wlen;
+ zstd->out.pos -= wlen;
+ }
+ } while (end_res > 0);
+ ZSTD_freeCStream(zstd->cstream);
+ free(zstd->buf_in);
+ free(zstd->buf_out);
+ } else if (zstd->dstream) {
+ ZSTD_freeDStream(zstd->dstream);
+ free(zstd->buf_in);
+ free(zstd->buf_out);
+ }
+ fret = fclose(zstd->file);
+ free(cookie);
+ return fret;
+}
+
+__extension__
+static cookie_io_functions_t iozstd = {
+ .read = (cookie_read_function_t*) zstdread,
+ .write = (cookie_write_function_t*)zstdwrite,
+ .seek = (cookie_seek_function_t*) zstdseek,
+ .close = (cookie_close_function_t*)zstdclose,
+};
+#else /* !HAS_ZSTD_H */
+# warning No support for .zst(d) format
+#endif /* !HAS_ZSTD_H */
+
#ifndef MIN
# define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif
@@ -685,6 +941,10 @@ static inline char autodetect(char **__restrict path, const char *__restrict che
what = 'l';
else if (strcmp(suff, "xz" ) == 0)
what = 'x';
+ else if (strcmp(suff, "zst" ) == 0)
+ what = 's';
+ else if (strcmp(suff, "zstd" ) == 0)
+ what = 's';
}
if (what == 'n' && *check == 'r') {
@@ -729,6 +989,17 @@ static inline char autodetect(char **__restrict path, const char *__restrict che
}
*suff = '\0';
+ if (stat(strcat(ext, ".zst"), &st) == 0) {
+ what = 's';
+ goto skip;
+ }
+ *suff = '\0';
+ if (stat(strcat(ext, ".zstd"), &st) == 0) {
+ what = 's';
+ goto skip;
+ }
+ *suff = '\0';
+
if ((fd = open(ext, O_RDONLY|O_NOCTTY)) < 0)
goto skip;
if (read(fd, m, sizeof(m)) == sizeof(m)) {
@@ -746,6 +1017,8 @@ static inline char autodetect(char **__restrict path, const char *__restrict che
what = 'l';
else if (m[0] == '\375' && m[1] == '7' && m[2] == 'z' && m[3] == 'X' && m[4] == 'Z')
what = 'x';
+ else if (m[0] >= 34 && m[0] <= 40 && m[1] == '\265' && m[2] == '\057' && m[3] == '\375')
+ what = 's';
}
close(fd);
skip:
@@ -1020,6 +1293,77 @@ FILE * fzopen(const char * path, const char * mode)
# endif /* !HAS_LZMADEC_H */
#endif /* !HAS_LZMA_H */
break;
+ case 's':
+#if defined(HAS_ZSTD_H)
+ {
+ zstdfile_t *__restrict cookie;
+ int level = 7;
+ int zret;
+# ifndef NO_WEAK
+ if ((ZSTD_createCStream) == 0 || (ZSTD_createDStream) == 0) {
+ errno = ENOSYS;
+ goto out;
+ }
+# endif
+ if (posix_memalign((void*)&cookie, sizeof(void*), alignof(zstdfile_t)) != 0)
+ goto out;
+ memset(cookie, 0, alignof(zstdfile_t));
+
+ if ((cookie->file = fopen(ext, check)) == NULL) {
+ free(cookie);
+ goto out;
+ }
+
+ n = strlen(mode);
+ for (i = 1; i < n; i++) {
+ if (mode[i] >= '1' && mode[i] <= '9') {
+ level = (int)mode[i];
+ break;
+ }
+ }
+
+ if (check[0] == 'w') {
+ cookie->cstream = ZSTD_createCStream();
+ if (!cookie->cstream) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+ } else {
+ cookie->dstream = ZSTD_createDStream();
+ if (!cookie->dstream) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+ }
+ cookie->level = level;
+ zret = zstdopen(cookie);
+
+ if (zret < 0) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+ if (!(ret = fopencookie((void*)cookie, check, iozstd))) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ cookie->stdio = ret;
+ }
+#else /* !HAS_ZSTD_H */
+ errno = ENOTSUP;
+#endif /* !HAS_ZSTD_H */
+ break;
default:
ret = fopen(ext, mode);
break;
@@ -1289,6 +1633,77 @@ FILE * fdzopen(int fildes, const char * mode, const char *what)
# endif /* !HAS_LZMADEC_H */
#endif /* !HAS_LZMA_H */
break;
+ case 's':
+#if defined(HAS_ZSTD_H)
+ {
+ zstdfile_t *__restrict cookie;
+ int level = 7;
+ int zret;
+# ifndef NO_WEAK
+ if ((ZSTD_createCStream) == 0 || (ZSTD_createDStream) == 0) {
+ errno = ENOSYS;
+ goto out;
+ }
+# endif
+ if (posix_memalign((void*)&cookie, sizeof(void*), alignof(zstdfile_t)) != 0)
+ goto out;
+ memset(cookie, 0, alignof(zstdfile_t));
+
+ if ((cookie->file = fdopen(fildes, check)) == NULL) {
+ free(cookie);
+ goto out;
+ }
+
+ n = strlen(mode);
+ for (i = 1; i < n; i++) {
+ if (mode[i] >= '1' && mode[i] <= '9') {
+ level = (int)mode[i];
+ break;
+ }
+ }
+
+ if (check[0] == 'w') {
+ cookie->cstream = ZSTD_createCStream();
+ if (!cookie->cstream) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+ } else {
+ cookie->dstream = ZSTD_createDStream();
+ if (!cookie->dstream) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+ }
+ cookie->level = level;
+ zret = zstdopen(cookie);
+
+ if (zret < 0) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+ if (!(ret = fopencookie((void*)cookie, check, iozstd))) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ cookie->stdio = ret;
+ }
+#else /* !HAS_ZSTD_H */
+ errno = ENOTSUP;
+#endif /* !HAS_ZSTD_H */
+ break;
default:
ret = fdopen(fildes, mode);
break;
diff --git a/zio.h.in b/zio.h.in
index f50ebd4..b71f5fd 100644
--- a/zio.h.in
+++ b/zio.h.in
@@ -1,8 +1,9 @@
/*
- * zio.h Provide an streamable interface to gziped/bzip2ed/LZW/LZMA files
+ * zio.h Provide an streamable interface to gziped/bzip2ed/LZW/LZMA/zst files
*
* Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
* Copyright 2013 Werner Fink, 2013 SuSE LINUX AG, Germany.
+ * Copyright 2021 Werner Fink, 2021 SUSE Software Solutions Germany GmbH, Germany.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/zioP.h b/zioP.h
index 4348676..91018c9 100644
--- a/zioP.h
+++ b/zioP.h
@@ -1,11 +1,12 @@
/*
* zioP.h Internal header for libzio, including required standard glibc
- * header, zlib.h, lzma.h or lzmadec.h, and bzlib.h.
- * Making the used libz, liblzma, and bzlib functions weak symbols.
+ * header, zlib.h, lzma.h or lzmadec.h, zstd.h, and bzlib.h.
+ * Making the used libz, liblzma, libzstd, and bzlib functions weak symbols.
*
* Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
* Copyright 2006 Werner Fink, 2006 SuSE Products GmbH, Germany.
* Copyright 2013 Werner Fink, 2013 SuSE Products GmbH, Germany.
+ * Copyright 2021 Werner Fink, 2021 SUSE Software Solutions Germany GmbH, Germany.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -135,6 +136,23 @@ weak_symbol(lzmadec_close);
# endif
#endif /* !HAS_LZMA_H */
+#if defined(HAS_ZSTD_H)
+# include <zstd.h>
+# ifndef NO_WEAK
+weak_symbol(ZSTD_initCStream);
+weak_symbol(ZSTD_initDStream);
+weak_symbol(ZSTD_createCStream);
+weak_symbol(ZSTD_createDStream);
+weak_symbol(ZSTD_compressStream);
+weak_symbol(ZSTD_decompressStream);
+weak_symbol(ZSTD_endStream);
+weak_symbol(ZSTD_freeCStream);
+weak_symbol(ZSTD_freeDStream);
+weak_symbol(ZSTD_isError);
+weak_symbol(ZSTD_getErrorName);
+# endif
+#endif
+
#if defined(HAVE_FOPENCOOKIE)
# undef HAVE_FUNOPEN
__extension__ typedef off_t zio_off_t;