PostgreSQL Source Code  git master
pgp-compress.c
Go to the documentation of this file.
1 /*
2  * pgp-compress.c
3  * ZIP and ZLIB compression via zlib.
4  *
5  * Copyright (c) 2005 Marko Kreen
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * contrib/pgcrypto/pgp-compress.c
30  */
31 
32 #include "postgres.h"
33 
34 #include "pgp.h"
35 #include "px.h"
36 
37 /*
38  * Compressed pkt writer
39  */
40 
41 #ifdef HAVE_LIBZ
42 
43 #include <zlib.h>
44 
45 #define ZIP_OUT_BUF 8192
46 #define ZIP_IN_BLOCK 8192
47 
48 struct ZipStat
49 {
50  uint8 type;
51  int buf_len;
52  int hdr_done;
53  z_stream stream;
54  uint8 buf[ZIP_OUT_BUF];
55 };
56 
57 static void *
58 z_alloc(void *priv, unsigned n_items, unsigned item_len)
59 {
60  return px_alloc(n_items * item_len);
61 }
62 
63 static void
64 z_free(void *priv, void *addr)
65 {
66  px_free(addr);
67 }
68 
69 static int
70 compress_init(PushFilter *next, void *init_arg, void **priv_p)
71 {
72  int res;
73  struct ZipStat *st;
74  PGP_Context *ctx = init_arg;
75  uint8 type = ctx->compress_algo;
76 
77  if (type != PGP_COMPR_ZLIB && type != PGP_COMPR_ZIP)
79 
80  /*
81  * init
82  */
83  st = px_alloc(sizeof(*st));
84  memset(st, 0, sizeof(*st));
85  st->buf_len = ZIP_OUT_BUF;
86  st->stream.zalloc = z_alloc;
87  st->stream.zfree = z_free;
88 
89  if (type == PGP_COMPR_ZIP)
90  res = deflateInit2(&st->stream, ctx->compress_level,
91  Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
92  else
93  res = deflateInit(&st->stream, ctx->compress_level);
94  if (res != Z_OK)
95  {
96  px_free(st);
98  }
99  *priv_p = st;
100 
101  return ZIP_IN_BLOCK;
102 }
103 
104 /* writes compressed data packet */
105 
106 /* can handle zero-len incoming data, but shouldn't */
107 static int
108 compress_process(PushFilter *next, void *priv, const uint8 *data, int len)
109 {
110  int res,
111  n_out;
112  struct ZipStat *st = priv;
113 
114  /*
115  * process data
116  */
117  while (len > 0)
118  {
119  st->stream.next_in = unconstify(uint8 *, data);
120  st->stream.avail_in = len;
121  st->stream.next_out = st->buf;
122  st->stream.avail_out = st->buf_len;
123  res = deflate(&st->stream, 0);
124  if (res != Z_OK)
126 
127  n_out = st->buf_len - st->stream.avail_out;
128  if (n_out > 0)
129  {
130  res = pushf_write(next, st->buf, n_out);
131  if (res < 0)
132  return res;
133  }
134  len = st->stream.avail_in;
135  }
136 
137  return 0;
138 }
139 
140 static int
141 compress_flush(PushFilter *next, void *priv)
142 {
143  int res,
144  zres,
145  n_out;
146  struct ZipStat *st = priv;
147 
148  st->stream.next_in = NULL;
149  st->stream.avail_in = 0;
150  while (1)
151  {
152  st->stream.next_out = st->buf;
153  st->stream.avail_out = st->buf_len;
154  zres = deflate(&st->stream, Z_FINISH);
155  if (zres != Z_STREAM_END && zres != Z_OK)
157  n_out = st->buf_len - st->stream.avail_out;
158  if (n_out > 0)
159  {
160  res = pushf_write(next, st->buf, n_out);
161  if (res < 0)
162  return res;
163  }
164  if (zres == Z_STREAM_END)
165  break;
166  }
167  return 0;
168 }
169 
170 static void
171 compress_free(void *priv)
172 {
173  struct ZipStat *st = priv;
174 
175  deflateEnd(&st->stream);
176  px_memset(st, 0, sizeof(*st));
177  px_free(st);
178 }
179 
180 static const PushFilterOps
181  compress_filter = {
182  compress_init, compress_process, compress_flush, compress_free
183 };
184 
185 int
187 {
188  return pushf_create(res, &compress_filter, ctx, dst);
189 }
190 
191 /*
192  * Decompress
193  */
194 struct DecomprData
195 {
196  int buf_len; /* = ZIP_OUT_BUF */
197  int buf_data; /* available data */
198  uint8 *pos;
199  z_stream stream;
200  int eof;
201  uint8 buf[ZIP_OUT_BUF];
202 };
203 
204 static int
205 decompress_init(void **priv_p, void *arg, PullFilter *src)
206 {
207  PGP_Context *ctx = arg;
208  struct DecomprData *dec;
209  int res;
210 
211  if (ctx->compress_algo != PGP_COMPR_ZLIB
212  && ctx->compress_algo != PGP_COMPR_ZIP)
214 
215  dec = px_alloc(sizeof(*dec));
216  memset(dec, 0, sizeof(*dec));
217  dec->buf_len = ZIP_OUT_BUF;
218  *priv_p = dec;
219 
220  dec->stream.zalloc = z_alloc;
221  dec->stream.zfree = z_free;
222 
223  if (ctx->compress_algo == PGP_COMPR_ZIP)
224  res = inflateInit2(&dec->stream, -15);
225  else
226  res = inflateInit(&dec->stream);
227  if (res != Z_OK)
228  {
229  px_free(dec);
230  px_debug("decompress_init: inflateInit error");
232  }
233 
234  return 0;
235 }
236 
237 static int
238 decompress_read(void *priv, PullFilter *src, int len,
239  uint8 **data_p, uint8 *buf, int buflen)
240 {
241  int res;
242  int flush;
243  struct DecomprData *dec = priv;
244 
245 restart:
246  if (dec->buf_data > 0)
247  {
248  if (len > dec->buf_data)
249  len = dec->buf_data;
250  *data_p = dec->pos;
251  dec->pos += len;
252  dec->buf_data -= len;
253  return len;
254  }
255 
256  if (dec->eof)
257  return 0;
258 
259  if (dec->stream.avail_in == 0)
260  {
261  uint8 *tmp;
262 
263  res = pullf_read(src, 8192, &tmp);
264  if (res < 0)
265  return res;
266  dec->stream.next_in = tmp;
267  dec->stream.avail_in = res;
268  }
269 
270  dec->stream.next_out = dec->buf;
271  dec->stream.avail_out = dec->buf_len;
272  dec->pos = dec->buf;
273 
274  /*
275  * Z_SYNC_FLUSH is tell zlib to output as much as possible. It should do
276  * it anyway (Z_NO_FLUSH), but seems to reserve the right not to. So lets
277  * follow the API.
278  */
279  flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH;
280  res = inflate(&dec->stream, flush);
281  if (res != Z_OK && res != Z_STREAM_END)
282  {
283  px_debug("decompress_read: inflate error: %d", res);
284  return PXE_PGP_CORRUPT_DATA;
285  }
286 
287  dec->buf_data = dec->buf_len - dec->stream.avail_out;
288  if (res == Z_STREAM_END)
289  dec->eof = 1;
290  goto restart;
291 }
292 
293 static void
294 decompress_free(void *priv)
295 {
296  struct DecomprData *dec = priv;
297 
298  inflateEnd(&dec->stream);
299  px_memset(dec, 0, sizeof(*dec));
300  px_free(dec);
301 }
302 
303 static const PullFilterOps
304  decompress_filter = {
305  decompress_init, decompress_read, decompress_free
306 };
307 
308 int
310 {
311  return pullf_create(res, &decompress_filter, ctx, src);
312 }
313 #else /* !HAVE_LIBZ */
314 
315 int
317 {
319 }
320 
321 int
323 {
325 }
326 
327 #endif
#define PXE_PGP_CORRUPT_DATA
Definition: px.h:78
static int32 next
Definition: blutils.c:213
int pullf_read(PullFilter *pf, int len, uint8 **data_p)
Definition: mbuf.c:260
int pullf_create(PullFilter **pf_p, const PullFilterOps *op, void *init_arg, PullFilter *src)
Definition: mbuf.c:204
#define px_free(p)
Definition: px.h:46
#define PXE_PGP_COMPRESSION_ERROR
Definition: px.h:83
unsigned char uint8
Definition: c.h:357
int pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
Definition: pgp-compress.c:316
int compress_level
Definition: pgp.h:146
#define PXE_PGP_UNSUPPORTED_COMPR
Definition: px.h:80
static char * buf
Definition: pg_test_fsync.c:67
int compress_algo
Definition: pgp.h:145
#define unconstify(underlying_type, expr)
Definition: c.h:1194
int pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
Definition: pgp-compress.c:322
int pushf_create(PushFilter **mp_p, const PushFilterOps *op, void *init_arg, PushFilter *next)
Definition: mbuf.c:371
void px_debug(const char *fmt,...)
Definition: px.c:152
#define px_alloc(s)
Definition: px.h:44
void * arg
int pushf_write(PushFilter *mp, const uint8 *data, int len)
Definition: mbuf.c:454
void px_memset(void *ptr, int c, size_t len)
Definition: px.c:126