diff --git a/Makefile-libostree.am b/Makefile-libostree.am index 30962068..5fd60006 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -41,6 +41,12 @@ libostree_1_la_SOURCES = \ src/libostree/ostree-checksum-input-stream.h \ src/libostree/ostree-chain-input-stream.c \ src/libostree/ostree-chain-input-stream.h \ + src/libostree/ostree-lzma-common.c \ + src/libostree/ostree-lzma-common.h \ + src/libostree/ostree-lzma-compressor.c \ + src/libostree/ostree-lzma-compressor.h \ + src/libostree/ostree-lzma-decompressor.c \ + src/libostree/ostree-lzma-decompressor.h \ src/libostree/ostree-varint.h \ src/libostree/ostree-varint.c \ src/libostree/ostree-diff.c \ @@ -83,9 +89,9 @@ libostree_1_la_SOURCES += src/libostree/ostree-libarchive-input-stream.h \ $(NULL) endif -libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree -DLOCALEDIR=\"$(datadir)/locale\" -DGPGVPATH=\"$(GPGVPATH)\" $(OT_INTERNAL_GIO_UNIX_CFLAGS) +libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree -DLOCALEDIR=\"$(datadir)/locale\" -DGPGVPATH=\"$(GPGVPATH)\" $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_DEP_LZMA_CFLAGS) libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions -export-symbols-regex '^ostree_' -libostree_1_la_LIBADD = libotutil.la libostree-kernel-args.la $(OT_INTERNAL_GIO_UNIX_LIBS) +libostree_1_la_LIBADD = libotutil.la libostree-kernel-args.la $(OT_INTERNAL_GIO_UNIX_LIBS) $(OT_DEP_LZMA_LIBS) if USE_LIBARCHIVE libostree_1_la_CFLAGS += $(OT_DEP_LIBARCHIVE_CFLAGS) diff --git a/configure.ac b/configure.ac index f5322ff8..9089ddc6 100644 --- a/configure.ac +++ b/configure.ac @@ -45,6 +45,9 @@ PKG_PROG_PKG_CONFIG GIO_DEPENDENCY="gio-unix-2.0 >= 2.34.0 libgsystem >= 2014.2" PKG_CHECK_MODULES(OT_DEP_GIO_UNIX, $GIO_DEPENDENCY) +dnl 5.1.0 is an arbitrary version here +PKG_CHECK_MODULES(OT_DEP_LZMA, liblzma >= 5.1.1alpha) + SOUP_DEPENDENCY="libsoup-2.4 >= 2.39.1" AC_ARG_WITH(soup, AS_HELP_STRING([--with-soup], [Use libsoup @<:@default=yes@:>@]), diff --git a/src/libostree/ostree-lzma-common.c b/src/libostree/ostree-lzma-common.c new file mode 100644 index 00000000..6993643c --- /dev/null +++ b/src/libostree/ostree-lzma-common.c @@ -0,0 +1,71 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "ostree-lzma-common.h" + +#include +#include +#include + +GConverterResult +_ostree_lzma_return (lzma_ret res, + GError **error) +{ + switch (res) + { + case LZMA_OK: + return G_CONVERTER_CONVERTED; + case LZMA_STREAM_END: + return G_CONVERTER_FINISHED; + case LZMA_NO_CHECK: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Stream is corrupt"); + return G_CONVERTER_ERROR; + case LZMA_UNSUPPORTED_CHECK: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot calculate integrity check"); + return G_CONVERTER_ERROR; + case LZMA_MEM_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Out of memory"); + return G_CONVERTER_ERROR; + case LZMA_MEMLIMIT_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Exceeded memory limit"); + return G_CONVERTER_ERROR; + case LZMA_FORMAT_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "File format not recognized"); + return G_CONVERTER_ERROR; + case LZMA_OPTIONS_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid or unsupported options"); + return G_CONVERTER_ERROR; + case LZMA_DATA_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Data is corrupt"); + return G_CONVERTER_ERROR; + default: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unrecognized LZMA error"); + return G_CONVERTER_ERROR; + } +} + diff --git a/src/libostree/ostree-lzma-common.h b/src/libostree/ostree-lzma-common.h new file mode 100644 index 00000000..17c8a64d --- /dev/null +++ b/src/libostree/ostree-lzma-common.h @@ -0,0 +1,28 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +GConverterResult _ostree_lzma_return (lzma_ret value, GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-lzma-compressor.c b/src/libostree/ostree-lzma-compressor.c new file mode 100644 index 00000000..c93d1086 --- /dev/null +++ b/src/libostree/ostree-lzma-compressor.c @@ -0,0 +1,212 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "ostree-lzma-compressor.h" +#include "ostree-lzma-common.h" + +#include +#include +#include + +enum { + PROP_0, + PROP_PARAMS +}; + +/** + * SECTION:ostree-lzma-compressor + * @short_description: LZMA compressor + * + * An an implementation of #GConverter that compresses data using + * LZMA. + */ + +static void _ostree_lzma_compressor_iface_init (GConverterIface *iface); + +/** + * OstreeLzmaCompressor: + * + * Zlib decompression + */ +struct _OstreeLzmaCompressor +{ + GObject parent_instance; + + GVariant *params; + lzma_stream lstream; + gboolean initialized; +}; + +G_DEFINE_TYPE_WITH_CODE (OstreeLzmaCompressor, _ostree_lzma_compressor, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, + _ostree_lzma_compressor_iface_init)) + +static void +_ostree_lzma_compressor_finalize (GObject *object) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (object); + + lzma_end (&self->lstream); + g_clear_pointer (&self->params, (GDestroyNotify)g_variant_unref); + + G_OBJECT_CLASS (_ostree_lzma_compressor_parent_class)->finalize (object); +} + +static void +_ostree_lzma_compressor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (object); + + switch (prop_id) + { + case PROP_PARAMS: + self->params = g_value_get_variant (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + +} + +static void +_ostree_lzma_compressor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (object); + + switch (prop_id) + { + case PROP_PARAMS: + g_value_set_variant (value, self->params); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +_ostree_lzma_compressor_init (OstreeLzmaCompressor *self) +{ + lzma_stream tmp = LZMA_STREAM_INIT; + self->lstream = tmp; +} + +static void +_ostree_lzma_compressor_class_init (OstreeLzmaCompressorClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = _ostree_lzma_compressor_finalize; + gobject_class->get_property = _ostree_lzma_compressor_get_property; + gobject_class->set_property = _ostree_lzma_compressor_set_property; + + g_object_class_install_property (gobject_class, + PROP_PARAMS, + g_param_spec_variant ("params", "", "", + G_VARIANT_TYPE ("a{sv}"), + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +OstreeLzmaCompressor * +_ostree_lzma_compressor_new (GVariant *params) +{ + return g_object_new (OSTREE_TYPE_LZMA_COMPRESSOR, + "params", params, + NULL); +} + +static void +_ostree_lzma_compressor_reset (GConverter *converter) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (converter); + + if (self->initialized) + { + lzma_stream tmp = LZMA_STREAM_INIT; + lzma_end (&self->lstream); + self->lstream = tmp; + self->initialized = FALSE; + } +} + +static GConverterResult +_ostree_lzma_compressor_convert (GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (converter); + int res; + lzma_action action; + + if (!self->initialized) + { + res = lzma_easy_encoder (&self->lstream, 8, LZMA_CHECK_CRC64); + if (res != LZMA_OK) + goto out; + self->initialized = TRUE; + } + + self->lstream.next_in = (void *)inbuf; + self->lstream.avail_in = inbuf_size; + + self->lstream.next_out = outbuf; + self->lstream.avail_out = outbuf_size; + + action = LZMA_RUN; + if (flags & G_CONVERTER_INPUT_AT_END) + action = LZMA_FINISH; + else if (flags & G_CONVERTER_FLUSH) + action = LZMA_SYNC_FLUSH; + + res = lzma_code (&self->lstream, action); + if (res != LZMA_OK && res != LZMA_STREAM_END) + goto out; + + *bytes_read = inbuf_size - self->lstream.avail_in; + *bytes_written = outbuf_size - self->lstream.avail_out; + + out: + return _ostree_lzma_return (res, error); +} + +static void +_ostree_lzma_compressor_iface_init (GConverterIface *iface) +{ + iface->convert = _ostree_lzma_compressor_convert; + iface->reset = _ostree_lzma_compressor_reset; +} diff --git a/src/libostree/ostree-lzma-compressor.h b/src/libostree/ostree-lzma-compressor.h new file mode 100644 index 00000000..ceb0fc57 --- /dev/null +++ b/src/libostree/ostree-lzma-compressor.h @@ -0,0 +1,44 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_LZMA_COMPRESSOR (_ostree_lzma_compressor_get_type ()) +#define OSTREE_LZMA_COMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_LZMA_COMPRESSOR, OstreeLzmaCompressor)) +#define OSTREE_LZMA_COMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_LZMA_COMPRESSOR, OstreeLzmaCompressorClass)) +#define OSTREE_IS_LZMA_COMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_LZMA_COMPRESSOR)) +#define OSTREE_IS_LZMA_COMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_LZMA_COMPRESSOR)) +#define OSTREE_LZMA_COMPRESSOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_LZMA_COMPRESSOR, OstreeLzmaCompressorClass)) + +typedef struct _OstreeLzmaCompressorClass OstreeLzmaCompressorClass; +typedef struct _OstreeLzmaCompressor OstreeLzmaCompressor; + +struct _OstreeLzmaCompressorClass +{ + GObjectClass parent_class; +}; + +GType _ostree_lzma_compressor_get_type (void) G_GNUC_CONST; + +OstreeLzmaCompressor *_ostree_lzma_compressor_new (GVariant *params); + +G_END_DECLS diff --git a/src/libostree/ostree-lzma-decompressor.c b/src/libostree/ostree-lzma-decompressor.c new file mode 100644 index 00000000..51630132 --- /dev/null +++ b/src/libostree/ostree-lzma-decompressor.c @@ -0,0 +1,137 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "ostree-lzma-decompressor.h" +#include "ostree-lzma-common.h" + +#include +#include +#include + +enum { + PROP_0, +}; + +static void _ostree_lzma_decompressor_iface_init (GConverterIface *iface); + +struct _OstreeLzmaDecompressor +{ + GObject parent_instance; + + lzma_stream lstream; + gboolean initialized; +}; + +G_DEFINE_TYPE_WITH_CODE (OstreeLzmaDecompressor, _ostree_lzma_decompressor, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, + _ostree_lzma_decompressor_iface_init)) + +static void +_ostree_lzma_decompressor_finalize (GObject *object) +{ + OstreeLzmaDecompressor *self; + + self = OSTREE_LZMA_DECOMPRESSOR (object); + lzma_end (&self->lstream); + + G_OBJECT_CLASS (_ostree_lzma_decompressor_parent_class)->finalize (object); +} + +static void +_ostree_lzma_decompressor_init (OstreeLzmaDecompressor *self) +{ + lzma_stream tmp = LZMA_STREAM_INIT; + self->lstream = tmp; +} + +static void +_ostree_lzma_decompressor_class_init (OstreeLzmaDecompressorClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = _ostree_lzma_decompressor_finalize; +} + +OstreeLzmaDecompressor * +_ostree_lzma_decompressor_new (void) +{ + return g_object_new (OSTREE_TYPE_LZMA_DECOMPRESSOR, NULL); +} + +static void +_ostree_lzma_decompressor_reset (GConverter *converter) +{ + OstreeLzmaDecompressor *self = OSTREE_LZMA_DECOMPRESSOR (converter); + + if (self->initialized) + { + lzma_stream tmp = LZMA_STREAM_INIT; + lzma_end (&self->lstream); + self->lstream = tmp; + self->initialized = FALSE; + } +} + +static GConverterResult +_ostree_lzma_decompressor_convert (GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error) +{ + OstreeLzmaDecompressor *self = OSTREE_LZMA_DECOMPRESSOR (converter); + int res; + + if (!self->initialized) + { + res = lzma_stream_decoder (&self->lstream, G_MAXUINT64, 0); + if (res != LZMA_OK) + goto out; + self->initialized = TRUE; + } + + self->lstream.next_in = (void *)inbuf; + self->lstream.avail_in = inbuf_size; + + self->lstream.next_out = outbuf; + self->lstream.avail_out = outbuf_size; + + res = lzma_code (&self->lstream, LZMA_RUN); + if (res != LZMA_OK && res != LZMA_STREAM_END) + goto out; + + *bytes_read = inbuf_size - self->lstream.avail_in; + *bytes_written = outbuf_size - self->lstream.avail_out; + + out: + return _ostree_lzma_return (res, error); +} + +static void +_ostree_lzma_decompressor_iface_init (GConverterIface *iface) +{ + iface->convert = _ostree_lzma_decompressor_convert; + iface->reset = _ostree_lzma_decompressor_reset; +} diff --git a/src/libostree/ostree-lzma-decompressor.h b/src/libostree/ostree-lzma-decompressor.h new file mode 100644 index 00000000..0916c829 --- /dev/null +++ b/src/libostree/ostree-lzma-decompressor.h @@ -0,0 +1,46 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_LZMA_DECOMPRESSOR (_ostree_lzma_decompressor_get_type ()) +#define OSTREE_LZMA_DECOMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_LZMA_DECOMPRESSOR, OstreeLzmaDecompressor)) +#define OSTREE_LZMA_DECOMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_LZMA_DECOMPRESSOR, OstreeLzmaDecompressorClass)) +#define OSTREE_IS_LZMA_DECOMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_LZMA_DECOMPRESSOR)) +#define OSTREE_IS_LZMA_DECOMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_LZMA_DECOMPRESSOR)) +#define OSTREE_LZMA_DECOMPRESSOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_LZMA_DECOMPRESSOR, OstreeLzmaDecompressorClass)) + +typedef struct _OstreeLzmaDecompressorClass OstreeLzmaDecompressorClass; +typedef struct _OstreeLzmaDecompressor OstreeLzmaDecompressor; + +struct _OstreeLzmaDecompressorClass +{ + GObjectClass parent_class; +}; + +GLIB_AVAILABLE_IN_ALL +GType _ostree_lzma_decompressor_get_type (void) G_GNUC_CONST; + +GLIB_AVAILABLE_IN_ALL +OstreeLzmaDecompressor *_ostree_lzma_decompressor_new (void); + +G_END_DECLS