PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 "px.h"
35 #include "pgp.h"
36 
37 
38 /*
39  * Compressed pkt writer
40  */
41 
42 #ifdef HAVE_LIBZ
43 
44 #include <zlib.h>
45 
46 #define ZIP_OUT_BUF 8192
47 #define ZIP_IN_BLOCK 8192
48 
49 struct ZipStat
50 {
51  uint8 type;
52  int buf_len;
53  int hdr_done;
54  z_stream stream;
55  uint8 buf[ZIP_OUT_BUF];
56 };
57 
58 static void *
59 z_alloc(void *priv, unsigned n_items, unsigned item_len)
60 {
61  return px_alloc(n_items * item_len);
62 }
63 
64 static void
65 z_free(void *priv, void *addr)
66 {
67  px_free(addr);
68 }
69 
70 static int
71 compress_init(PushFilter *next, void *init_arg, void **priv_p)
72 {
73  int res;
74  struct ZipStat *st;
75  PGP_Context *ctx = init_arg;
76  uint8 type = ctx->compress_algo;
77 
78  if (type != PGP_COMPR_ZLIB && type != PGP_COMPR_ZIP)
80 
81  /*
82  * init
83  */
84  st = px_alloc(sizeof(*st));
85  memset(st, 0, sizeof(*st));
86  st->buf_len = ZIP_OUT_BUF;
87  st->stream.zalloc = z_alloc;
88  st->stream.zfree = z_free;
89 
90  if (type == PGP_COMPR_ZIP)
91  res = deflateInit2(&st->stream, ctx->compress_level,
92  Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
93  else
94  res = deflateInit(&st->stream, ctx->compress_level);
95  if (res != Z_OK)
96  {
97  px_free(st);
99  }
100  *priv_p = st;
101 
102  return ZIP_IN_BLOCK;
103 }
104 
105 /* writes compressed data packet */
106 
107 /* can handle zero-len incoming data, but shouldn't */
108 static int
109 compress_process(PushFilter *next, void *priv, const uint8 *data, int len)
110 {
111  int res,
112  n_out;
113  struct ZipStat *st = priv;
114 
115  /*
116  * process data
117  */
118  while (len > 0)
119  {
120  st->stream.next_in = (void *) data;
121  st->stream.avail_in = len;
122  st->stream.next_out = st->buf;
123  st->stream.avail_out = st->buf_len;
124  res = deflate(&st->stream, 0);
125  if (res != Z_OK)
127 
128  n_out = st->buf_len - st->stream.avail_out;
129  if (n_out > 0)
130  {
131  res = pushf_write(next, st->buf, n_out);
132  if (res < 0)
133  return res;
134  }
135  len = st->stream.avail_in;
136  }
137 
138  return 0;
139 }
140 
141 static int
142 compress_flush(PushFilter *next, void *priv)
143 {
144  int res,
145  zres,
146  n_out;
147  struct ZipStat *st = priv;
148 
149  st->stream.next_in = NULL;
150  st->stream.avail_in = 0;
151  while (1)
152  {
153  st->stream.next_out = st->buf;
154  st->stream.avail_out = st->buf_len;
155  zres = deflate(&st->stream, Z_FINISH);
156  if (zres != Z_STREAM_END && zres != Z_OK)
158  n_out = st->buf_len - st->stream.avail_out;
159  if (n_out > 0)
160  {
161  res = pushf_write(next, st->buf, n_out);
162  if (res < 0)
163  return res;
164  }
165  if (zres == Z_STREAM_END)
166  break;
167  }
168  return 0;
169 }
170 
171 static void
172 compress_free(void *priv)
173 {
174  struct ZipStat *st = priv;
175 
176  deflateEnd(&st->stream);
177  px_memset(st, 0, sizeof(*st));
178  px_free(st);
179 }
180 
181 static const PushFilterOps
182  compress_filter = {
183  compress_init, compress_process, compress_flush, compress_free
184 };
185 
186 int
188 {
189  return pushf_create(res, &compress_filter, ctx, dst);
190 }
191 
192 /*
193  * Decompress
194  */
195 struct DecomprData
196 {
197  int buf_len; /* = ZIP_OUT_BUF */
198  int buf_data; /* available data */
199  uint8 *pos;
200  z_stream stream;
201  int eof;
202  uint8 buf[ZIP_OUT_BUF];
203 };
204 
205 static int
206 decompress_init(void **priv_p, void *arg, PullFilter *src)
207 {
208  PGP_Context *ctx = arg;
209  struct DecomprData *dec;
210  int res;
211 
212  if (ctx->compress_algo != PGP_COMPR_ZLIB
213  && ctx->compress_algo != PGP_COMPR_ZIP)
215 
216  dec = px_alloc(sizeof(*dec));
217  memset(dec, 0, sizeof(*dec));
218  dec->buf_len = ZIP_OUT_BUF;
219  *priv_p = dec;
220 
221  dec->stream.zalloc = z_alloc;
222  dec->stream.zfree = z_free;
223 
224  if (ctx->compress_algo == PGP_COMPR_ZIP)
225  res = inflateInit2(&dec->stream, -15);
226  else
227  res = inflateInit(&dec->stream);
228  if (res != Z_OK)
229  {
230  px_free(dec);
231  px_debug("decompress_init: inflateInit error");
233  }
234 
235  return 0;
236 }
237 
238 static int
239 decompress_read(void *priv, PullFilter *src, int len,
240  uint8 **data_p, uint8 *buf, int buflen)
241 {
242  int res;
243  int flush;
244  struct DecomprData *dec = priv;
245 
246 restart:
247  if (dec->buf_data > 0)
248  {
249  if (len > dec->buf_data)
250  len = dec->buf_data;
251  *data_p = dec->pos;
252  dec->pos += len;
253  dec->buf_data -= len;
254  return len;
255  }
256 
257  if (dec->eof)
258  return 0;
259 
260  if (dec->stream.avail_in == 0)
261  {
262  uint8 *tmp;
263 
264  res = pullf_read(src, 8192, &tmp);
265  if (res < 0)
266  return res;
267  dec->stream.next_in = tmp;
268  dec->stream.avail_in = res;
269  }
270 
271  dec->stream.next_out = dec->buf;
272  dec->stream.avail_out = dec->buf_len;
273  dec->pos = dec->buf;
274 
275  /*
276  * Z_SYNC_FLUSH is tell zlib to output as much as possible. It should do
277  * it anyway (Z_NO_FLUSH), but seems to reserve the right not to. So lets
278  * follow the API.
279  */
280  flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH;
281  res = inflate(&dec->stream, flush);
282  if (res != Z_OK && res != Z_STREAM_END)
283  {
284  px_debug("decompress_read: inflate error: %d", res);
285  return PXE_PGP_CORRUPT_DATA;
286  }
287 
288  dec->buf_data = dec->buf_len - dec->stream.avail_out;
289  if (res == Z_STREAM_END)
290  dec->eof = 1;
291  goto restart;
292 }
293 
294 static void
295 decompress_free(void *priv)
296 {
297  struct DecomprData *dec = priv;
298 
299  inflateEnd(&dec->stream);
300  px_memset(dec, 0, sizeof(*dec));
301  px_free(dec);
302 }
303 
304 static const PullFilterOps
305  decompress_filter = {
306  decompress_init, decompress_read, decompress_free
307 };
308 
309 int
311 {
312  return pullf_create(res, &decompress_filter, ctx, src);
313 }
314 #else /* !HAVE_ZLIB */
315 
316 int
318 {
320 }
321 
322 int
324 {
326 }
327 
328 #endif
#define PXE_PGP_CORRUPT_DATA
Definition: px.h:81
static int32 next
Definition: blutils.c:210
int pullf_read(PullFilter *pf, int len, uint8 **data_p)
Definition: mbuf.c:262
int pullf_create(PullFilter **pf_p, const PullFilterOps *op, void *init_arg, PullFilter *src)
Definition: mbuf.c:206
#define px_free(p)
Definition: px.h:46
#define PXE_PGP_COMPRESSION_ERROR
Definition: px.h:86
unsigned char uint8
Definition: c.h:256
int pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
Definition: pgp-compress.c:317
int compress_level
Definition: pgp.h:146
#define PXE_PGP_UNSUPPORTED_COMPR
Definition: px.h:83
static char * buf
Definition: pg_test_fsync.c:67
int compress_algo
Definition: pgp.h:145
int pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
Definition: pgp-compress.c:323
int pushf_create(PushFilter **mp_p, const PushFilterOps *op, void *init_arg, PushFilter *next)
Definition: mbuf.c:373
void px_debug(const char *fmt,...)
Definition: px.c:160
#define px_alloc(s)
Definition: px.h:44
void * arg
int pushf_write(PushFilter *mp, const uint8 *data, int len)
Definition: mbuf.c:456
void px_memset(void *ptr, int c, size_t len)
Definition: px.c:134