PostgreSQL Source Code git master
compress_lz4.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * compress_lz4.c
4 * Routines for archivers to write a LZ4 compressed data stream.
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/bin/pg_dump/compress_lz4.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres_fe.h"
15#include <unistd.h>
16
17#include "compress_lz4.h"
18#include "pg_backup_utils.h"
19
20#ifdef USE_LZ4
21#include <lz4frame.h>
22
23/*
24 * LZ4F_HEADER_SIZE_MAX first appeared in v1.7.5 of the library.
25 * Redefine it for installations with a lesser version.
26 */
27#ifndef LZ4F_HEADER_SIZE_MAX
28#define LZ4F_HEADER_SIZE_MAX 32
29#endif
30
31/*---------------------------------
32 * Common to both compression APIs
33 *---------------------------------
34 */
35
36/*
37 * (de)compression state used by both the Compressor and Stream APIs.
38 */
39typedef struct LZ4State
40{
41 /*
42 * Used by the Stream API to keep track of the file stream.
43 */
44 FILE *fp;
45
46 LZ4F_preferences_t prefs;
47
48 LZ4F_compressionContext_t ctx;
49 LZ4F_decompressionContext_t dtx;
50
51 /*
52 * Used by the Stream API's lazy initialization.
53 */
54 bool inited;
55
56 /*
57 * Used by the Stream API to distinguish between compression and
58 * decompression operations.
59 */
60 bool compressing;
61
62 /*
63 * I/O buffer area.
64 */
65 char *buffer; /* buffer for compressed data */
66 size_t buflen; /* allocated size of buffer */
67 size_t bufdata; /* amount of valid data currently in buffer */
68 /* These fields are used only while decompressing: */
69 size_t bufnext; /* next buffer position to decompress */
70 char *outbuf; /* buffer for decompressed data */
71 size_t outbuflen; /* allocated size of outbuf */
72 size_t outbufdata; /* amount of valid data currently in outbuf */
73 size_t outbufnext; /* next outbuf position to return */
74
75 /*
76 * Used by both APIs to keep track of error codes.
77 */
78 size_t errcode;
79} LZ4State;
80
81/*
82 * LZ4State_compression_init
83 * Initialize the required LZ4State members for compression.
84 *
85 * Write the LZ4 frame header in a buffer keeping track of its length. Users of
86 * this function can choose when and how to write the header to a file stream.
87 *
88 * Returns true on success. In case of a failure returns false, and stores the
89 * error code in state->errcode.
90 */
91static bool
92LZ4State_compression_init(LZ4State *state)
93{
94 size_t status;
95
96 /*
97 * Compute size needed for buffer, assuming we will present at most
98 * DEFAULT_IO_BUFFER_SIZE input bytes at a time.
99 */
100 state->buflen = LZ4F_compressBound(DEFAULT_IO_BUFFER_SIZE, &state->prefs);
101
102 /*
103 * Add some slop to ensure we're not forced to flush every time.
104 *
105 * The present slop factor of 50% is chosen so that the typical output
106 * block size is about 128K when DEFAULT_IO_BUFFER_SIZE = 128K. We might
107 * need a different slop factor to maintain that equivalence if
108 * DEFAULT_IO_BUFFER_SIZE is changed dramatically.
109 */
110 state->buflen += state->buflen / 2;
111
112 /*
113 * LZ4F_compressBegin requires a buffer that is greater or equal to
114 * LZ4F_HEADER_SIZE_MAX. Verify that the requirement is met.
115 */
116 if (state->buflen < LZ4F_HEADER_SIZE_MAX)
117 state->buflen = LZ4F_HEADER_SIZE_MAX;
118
119 status = LZ4F_createCompressionContext(&state->ctx, LZ4F_VERSION);
120 if (LZ4F_isError(status))
121 {
122 state->errcode = status;
123 return false;
124 }
125
126 state->buffer = pg_malloc(state->buflen);
127
128 /*
129 * Insert LZ4 header into buffer.
130 */
131 status = LZ4F_compressBegin(state->ctx,
132 state->buffer, state->buflen,
133 &state->prefs);
134 if (LZ4F_isError(status))
135 {
136 state->errcode = status;
137 return false;
138 }
139
140 state->bufdata = status;
141
142 return true;
143}
144
145/*----------------------
146 * Compressor API
147 *----------------------
148 */
149
150/* Private routines that support LZ4 compressed data I/O */
151
152static void
153ReadDataFromArchiveLZ4(ArchiveHandle *AH, CompressorState *cs)
154{
155 size_t r;
156 size_t readbuflen;
157 char *outbuf;
158 char *readbuf;
159 LZ4F_decompressionContext_t ctx = NULL;
160 LZ4F_decompressOptions_t dec_opt;
161 LZ4F_errorCode_t status;
162
163 memset(&dec_opt, 0, sizeof(dec_opt));
164 status = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
165 if (LZ4F_isError(status))
166 pg_fatal("could not create LZ4 decompression context: %s",
167 LZ4F_getErrorName(status));
168
171 readbuflen = DEFAULT_IO_BUFFER_SIZE;
172 while ((r = cs->readF(AH, &readbuf, &readbuflen)) > 0)
173 {
174 char *readp;
175 char *readend;
176
177 /* Process one chunk */
178 readp = readbuf;
179 readend = readbuf + r;
180 while (readp < readend)
181 {
182 size_t out_size = DEFAULT_IO_BUFFER_SIZE;
183 size_t read_size = readend - readp;
184
185 status = LZ4F_decompress(ctx, outbuf, &out_size,
186 readp, &read_size, &dec_opt);
187 if (LZ4F_isError(status))
188 pg_fatal("could not decompress: %s",
189 LZ4F_getErrorName(status));
190
191 ahwrite(outbuf, 1, out_size, AH);
192 readp += read_size;
193 }
194 }
195
196 pg_free(outbuf);
197 pg_free(readbuf);
198
199 status = LZ4F_freeDecompressionContext(ctx);
200 if (LZ4F_isError(status))
201 pg_fatal("could not free LZ4 decompression context: %s",
202 LZ4F_getErrorName(status));
203}
204
205static void
206WriteDataToArchiveLZ4(ArchiveHandle *AH, CompressorState *cs,
207 const void *data, size_t dLen)
208{
209 LZ4State *state = (LZ4State *) cs->private_data;
210 size_t remaining = dLen;
211
212 while (remaining > 0)
213 {
214 size_t chunk;
215 size_t required;
216 size_t status;
217
218 /* We don't try to present more than DEFAULT_IO_BUFFER_SIZE bytes */
219 chunk = Min(remaining, (size_t) DEFAULT_IO_BUFFER_SIZE);
220
221 /* If not enough space, must flush buffer */
222 required = LZ4F_compressBound(chunk, &state->prefs);
223 if (required > state->buflen - state->bufdata)
224 {
225 cs->writeF(AH, state->buffer, state->bufdata);
226 state->bufdata = 0;
227 }
228
229 status = LZ4F_compressUpdate(state->ctx,
230 state->buffer + state->bufdata,
231 state->buflen - state->bufdata,
232 data, chunk, NULL);
233
234 if (LZ4F_isError(status))
235 pg_fatal("could not compress data: %s",
236 LZ4F_getErrorName(status));
237
238 state->bufdata += status;
239
240 data = ((const char *) data) + chunk;
241 remaining -= chunk;
242 }
243}
244
245static void
246EndCompressorLZ4(ArchiveHandle *AH, CompressorState *cs)
247{
248 LZ4State *state = (LZ4State *) cs->private_data;
249 size_t required;
250 size_t status;
251
252 /* Nothing needs to be done */
253 if (!state)
254 return;
255
256 /* We might need to flush the buffer to make room for LZ4F_compressEnd */
257 required = LZ4F_compressBound(0, &state->prefs);
258 if (required > state->buflen - state->bufdata)
259 {
260 cs->writeF(AH, state->buffer, state->bufdata);
261 state->bufdata = 0;
262 }
263
264 status = LZ4F_compressEnd(state->ctx,
265 state->buffer + state->bufdata,
266 state->buflen - state->bufdata,
267 NULL);
268 if (LZ4F_isError(status))
269 pg_fatal("could not end compression: %s",
270 LZ4F_getErrorName(status));
271 state->bufdata += status;
272
273 /* Write the final bufferload */
274 cs->writeF(AH, state->buffer, state->bufdata);
275
276 status = LZ4F_freeCompressionContext(state->ctx);
277 if (LZ4F_isError(status))
278 pg_fatal("could not end compression: %s",
279 LZ4F_getErrorName(status));
280
281 pg_free(state->buffer);
282 pg_free(state);
283
284 cs->private_data = NULL;
285}
286
287/*
288 * Public routines that support LZ4 compressed data I/O
289 */
290void
292{
293 LZ4State *state;
294
295 cs->readData = ReadDataFromArchiveLZ4;
296 cs->writeData = WriteDataToArchiveLZ4;
297 cs->end = EndCompressorLZ4;
298
299 cs->compression_spec = compression_spec;
300
301 /*
302 * Read operations have access to the whole input. No state needs to be
303 * carried between calls.
304 */
305 if (cs->readF)
306 return;
307
308 state = pg_malloc0(sizeof(*state));
309 if (cs->compression_spec.level >= 0)
310 state->prefs.compressionLevel = cs->compression_spec.level;
311
312 if (!LZ4State_compression_init(state))
313 pg_fatal("could not initialize LZ4 compression: %s",
314 LZ4F_getErrorName(state->errcode));
315
316 cs->private_data = state;
317}
318
319/*----------------------
320 * Compress Stream API
321 *----------------------
322 */
323
324
325/*
326 * LZ4 equivalent to feof() or gzeof(). Return true iff there is no
327 * more buffered data and the end of the input file has been reached.
328 */
329static bool
330LZ4Stream_eof(CompressFileHandle *CFH)
331{
332 LZ4State *state = (LZ4State *) CFH->private_data;
333
334 return state->outbufnext >= state->outbufdata &&
335 state->bufnext >= state->bufdata &&
336 feof(state->fp);
337}
338
339static const char *
340LZ4Stream_get_error(CompressFileHandle *CFH)
341{
342 LZ4State *state = (LZ4State *) CFH->private_data;
343 const char *errmsg;
344
345 if (LZ4F_isError(state->errcode))
346 errmsg = LZ4F_getErrorName(state->errcode);
347 else
348 errmsg = strerror(errno);
349
350 return errmsg;
351}
352
353/*
354 * Initialize an already alloc'ed LZ4State struct for subsequent calls.
355 *
356 * Creates the necessary contexts for either compression or decompression. When
357 * compressing data (indicated by compressing=true), it additionally writes the
358 * LZ4 header in the output buffer.
359 *
360 * It's expected that a not-yet-initialized LZ4State will be zero-filled.
361 *
362 * Returns true on success. In case of a failure returns false, and stores the
363 * error code in state->errcode.
364 */
365static bool
366LZ4Stream_init(LZ4State *state, bool compressing)
367{
368 size_t status;
369
370 if (state->inited)
371 return true;
372
373 state->compressing = compressing;
374
375 if (state->compressing)
376 {
377 if (!LZ4State_compression_init(state))
378 return false;
379 }
380 else
381 {
382 status = LZ4F_createDecompressionContext(&state->dtx, LZ4F_VERSION);
383 if (LZ4F_isError(status))
384 {
385 state->errcode = status;
386 return false;
387 }
388
390 state->buffer = pg_malloc(state->buflen);
391 state->outbuflen = DEFAULT_IO_BUFFER_SIZE;
392 state->outbuf = pg_malloc(state->outbuflen);
393 }
394
395 state->inited = true;
396 return true;
397}
398
399/*
400 * The workhorse for reading decompressed content out of an LZ4 compressed
401 * stream.
402 *
403 * It will read up to 'ptrsize' decompressed content, or up to the new line
404 * char if one is found first when the eol_flag is set.
405 *
406 * Returns the number of bytes of decompressed data copied into the ptr
407 * buffer, or -1 in case of error.
408 */
409static int
410LZ4Stream_read_internal(LZ4State *state, void *ptr, int ptrsize, bool eol_flag)
411{
412 int dsize = 0;
413 int remaining = ptrsize;
414
415 /* Lazy init */
416 if (!LZ4Stream_init(state, false /* decompressing */ ))
417 {
418 pg_log_error("unable to initialize LZ4 library: %s",
419 LZ4F_getErrorName(state->errcode));
420 return -1;
421 }
422
423 /* Loop until postcondition is satisfied */
424 while (remaining > 0)
425 {
426 /*
427 * If we already have some decompressed data, return that.
428 */
429 if (state->outbufnext < state->outbufdata)
430 {
431 char *outptr = state->outbuf + state->outbufnext;
432 size_t readlen = state->outbufdata - state->outbufnext;
433 bool eol_found = false;
434
435 if (readlen > remaining)
436 readlen = remaining;
437 /* If eol_flag is set, don't read beyond a newline */
438 if (eol_flag)
439 {
440 char *eolptr = memchr(outptr, '\n', readlen);
441
442 if (eolptr)
443 {
444 readlen = eolptr - outptr + 1;
445 eol_found = true;
446 }
447 }
448 memcpy(ptr, outptr, readlen);
449 ptr = ((char *) ptr) + readlen;
450 state->outbufnext += readlen;
451 dsize += readlen;
452 remaining -= readlen;
453 if (eol_found || remaining == 0)
454 break;
455 /* We must have emptied outbuf */
456 Assert(state->outbufnext >= state->outbufdata);
457 }
458
459 /*
460 * If we don't have any pending compressed data, load more into
461 * state->buffer.
462 */
463 if (state->bufnext >= state->bufdata)
464 {
465 size_t rsize;
466
467 rsize = fread(state->buffer, 1, state->buflen, state->fp);
468 if (rsize < state->buflen && !feof(state->fp))
469 {
470 pg_log_error("could not read from input file: %m");
471 return -1;
472 }
473 if (rsize == 0)
474 break; /* must be EOF */
475 state->bufdata = rsize;
476 state->bufnext = 0;
477 }
478
479 /*
480 * Decompress some data into state->outbuf.
481 */
482 {
483 size_t status;
484 size_t outlen = state->outbuflen;
485 size_t inlen = state->bufdata - state->bufnext;
486
487 status = LZ4F_decompress(state->dtx,
488 state->outbuf, &outlen,
489 state->buffer + state->bufnext,
490 &inlen,
491 NULL);
492 if (LZ4F_isError(status))
493 {
494 state->errcode = status;
495 pg_log_error("could not read from input file: %s",
496 LZ4F_getErrorName(state->errcode));
497 return -1;
498 }
499 state->bufnext += inlen;
500 state->outbufdata = outlen;
501 state->outbufnext = 0;
502 }
503 }
504
505 return dsize;
506}
507
508/*
509 * Compress size bytes from ptr and write them to the stream.
510 */
511static void
512LZ4Stream_write(const void *ptr, size_t size, CompressFileHandle *CFH)
513{
514 LZ4State *state = (LZ4State *) CFH->private_data;
515 size_t remaining = size;
516
517 /* Lazy init */
518 if (!LZ4Stream_init(state, true))
519 pg_fatal("unable to initialize LZ4 library: %s",
520 LZ4F_getErrorName(state->errcode));
521
522 while (remaining > 0)
523 {
524 size_t chunk;
525 size_t required;
526 size_t status;
527
528 /* We don't try to present more than DEFAULT_IO_BUFFER_SIZE bytes */
529 chunk = Min(remaining, (size_t) DEFAULT_IO_BUFFER_SIZE);
530
531 /* If not enough space, must flush buffer */
532 required = LZ4F_compressBound(chunk, &state->prefs);
533 if (required > state->buflen - state->bufdata)
534 {
535 errno = 0;
536 if (fwrite(state->buffer, 1, state->bufdata, state->fp) != state->bufdata)
537 {
538 errno = (errno) ? errno : ENOSPC;
539 pg_fatal("error during writing: %m");
540 }
541 state->bufdata = 0;
542 }
543
544 status = LZ4F_compressUpdate(state->ctx,
545 state->buffer + state->bufdata,
546 state->buflen - state->bufdata,
547 ptr, chunk, NULL);
548 if (LZ4F_isError(status))
549 pg_fatal("error during writing: %s", LZ4F_getErrorName(status));
550 state->bufdata += status;
551
552 ptr = ((const char *) ptr) + chunk;
553 remaining -= chunk;
554 }
555}
556
557/*
558 * fread() equivalent implementation for LZ4 compressed files.
559 */
560static size_t
561LZ4Stream_read(void *ptr, size_t size, CompressFileHandle *CFH)
562{
563 LZ4State *state = (LZ4State *) CFH->private_data;
564 int ret;
565
566 if ((ret = LZ4Stream_read_internal(state, ptr, size, false)) < 0)
567 pg_fatal("could not read from input file: %s", LZ4Stream_get_error(CFH));
568
569 return (size_t) ret;
570}
571
572/*
573 * fgetc() equivalent implementation for LZ4 compressed files.
574 */
575static int
576LZ4Stream_getc(CompressFileHandle *CFH)
577{
578 LZ4State *state = (LZ4State *) CFH->private_data;
579 unsigned char c;
580
581 if (LZ4Stream_read_internal(state, &c, 1, false) <= 0)
582 {
583 if (!LZ4Stream_eof(CFH))
584 pg_fatal("could not read from input file: %s", LZ4Stream_get_error(CFH));
585 else
586 pg_fatal("could not read from input file: end of file");
587 }
588
589 return c;
590}
591
592/*
593 * fgets() equivalent implementation for LZ4 compressed files.
594 */
595static char *
596LZ4Stream_gets(char *ptr, int size, CompressFileHandle *CFH)
597{
598 LZ4State *state = (LZ4State *) CFH->private_data;
599 int ret;
600
601 ret = LZ4Stream_read_internal(state, ptr, size - 1, true);
602
603 /*
604 * LZ4Stream_read_internal returning 0 or -1 means that it was either an
605 * EOF or an error, but gets_func is defined to return NULL in either case
606 * so we can treat both the same here.
607 */
608 if (ret <= 0)
609 return NULL;
610
611 /*
612 * Our caller expects the return string to be NULL terminated and we know
613 * that ret is greater than zero.
614 */
615 ptr[ret - 1] = '\0';
616
617 return ptr;
618}
619
620/*
621 * Finalize (de)compression of a stream. When compressing it will write any
622 * remaining content and/or generated footer from the LZ4 API.
623 */
624static bool
625LZ4Stream_close(CompressFileHandle *CFH)
626{
627 FILE *fp;
628 LZ4State *state = (LZ4State *) CFH->private_data;
629 size_t required;
630 size_t status;
631 int ret;
632
633 fp = state->fp;
634 if (state->inited)
635 {
636 if (state->compressing)
637 {
638 /* We might need to flush the buffer to make room */
639 required = LZ4F_compressBound(0, &state->prefs);
640 if (required > state->buflen - state->bufdata)
641 {
642 errno = 0;
643 if (fwrite(state->buffer, 1, state->bufdata, state->fp) != state->bufdata)
644 {
645 errno = (errno) ? errno : ENOSPC;
646 pg_log_error("could not write to output file: %m");
647 }
648 state->bufdata = 0;
649 }
650
651 status = LZ4F_compressEnd(state->ctx,
652 state->buffer + state->bufdata,
653 state->buflen - state->bufdata,
654 NULL);
655 if (LZ4F_isError(status))
656 {
657 pg_log_error("could not end compression: %s",
658 LZ4F_getErrorName(status));
659 }
660 else
661 state->bufdata += status;
662
663 errno = 0;
664 if (fwrite(state->buffer, 1, state->bufdata, state->fp) != state->bufdata)
665 {
666 errno = (errno) ? errno : ENOSPC;
667 pg_log_error("could not write to output file: %m");
668 }
669
670 status = LZ4F_freeCompressionContext(state->ctx);
671 if (LZ4F_isError(status))
672 pg_log_error("could not end compression: %s",
673 LZ4F_getErrorName(status));
674 }
675 else
676 {
677 status = LZ4F_freeDecompressionContext(state->dtx);
678 if (LZ4F_isError(status))
679 pg_log_error("could not end decompression: %s",
680 LZ4F_getErrorName(status));
681 pg_free(state->outbuf);
682 }
683
684 pg_free(state->buffer);
685 }
686
687 pg_free(state);
688 CFH->private_data = NULL;
689
690 errno = 0;
691 ret = fclose(fp);
692 if (ret != 0)
693 {
694 pg_log_error("could not close file: %m");
695 return false;
696 }
697
698 return true;
699}
700
701static bool
702LZ4Stream_open(const char *path, int fd, const char *mode,
704{
705 LZ4State *state = (LZ4State *) CFH->private_data;
706
707 if (fd >= 0)
708 state->fp = fdopen(dup(fd), mode);
709 else
710 state->fp = fopen(path, mode);
711 if (state->fp == NULL)
712 {
713 state->errcode = errno;
714 return false;
715 }
716
717 return true;
718}
719
720static bool
721LZ4Stream_open_write(const char *path, const char *mode, CompressFileHandle *CFH)
722{
723 char *fname;
724 int save_errno;
725 bool ret;
726
727 fname = psprintf("%s.lz4", path);
728 ret = CFH->open_func(fname, -1, mode, CFH);
729
730 save_errno = errno;
731 pg_free(fname);
732 errno = save_errno;
733
734 return ret;
735}
736
737/*
738 * Public routines
739 */
740void
742 const pg_compress_specification compression_spec)
743{
744 LZ4State *state;
745
746 CFH->open_func = LZ4Stream_open;
747 CFH->open_write_func = LZ4Stream_open_write;
748 CFH->read_func = LZ4Stream_read;
749 CFH->write_func = LZ4Stream_write;
750 CFH->gets_func = LZ4Stream_gets;
751 CFH->getc_func = LZ4Stream_getc;
752 CFH->eof_func = LZ4Stream_eof;
753 CFH->close_func = LZ4Stream_close;
754 CFH->get_error_func = LZ4Stream_get_error;
755
756 CFH->compression_spec = compression_spec;
757 state = pg_malloc0(sizeof(*state));
758 if (CFH->compression_spec.level >= 0)
759 state->prefs.compressionLevel = CFH->compression_spec.level;
760
761 CFH->private_data = state;
762}
763#else /* USE_LZ4 */
764void
766 const pg_compress_specification compression_spec)
767{
768 pg_fatal("this build does not support compression with %s", "LZ4");
769}
770
771void
773 const pg_compress_specification compression_spec)
774{
775 pg_fatal("this build does not support compression with %s", "LZ4");
776}
777#endif /* USE_LZ4 */
#define Min(x, y)
Definition: c.h:1008
#define DEFAULT_IO_BUFFER_SIZE
Definition: compress_io.h:27
void InitCompressFileHandleLZ4(CompressFileHandle *CFH, const pg_compress_specification compression_spec)
Definition: compress_lz4.c:772
void InitCompressorLZ4(CompressorState *cs, const pg_compress_specification compression_spec)
Definition: compress_lz4.c:765
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
void pg_free(void *ptr)
Definition: fe_memutils.c:105
Assert(PointerIsAligned(start, uint64))
int remaining
Definition: informix.c:692
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
#define pg_log_error(...)
Definition: logging.h:106
void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
#define pg_fatal(...)
static PgChecksumMode mode
Definition: pg_checksums.c:56
const void * data
while(p+4<=pend)
#define strerror
Definition: port.h:252
char * c
static int fd(const char *x, int i)
Definition: preproc-init.c:105
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
char *(* gets_func)(char *s, int size, CompressFileHandle *CFH)
Definition: compress_io.h:153
bool(* open_write_func)(const char *path, const char *mode, CompressFileHandle *CFH)
Definition: compress_io.h:122
int(* getc_func)(CompressFileHandle *CFH)
Definition: compress_io.h:162
const char *(* get_error_func)(CompressFileHandle *CFH)
Definition: compress_io.h:182
bool(* eof_func)(CompressFileHandle *CFH)
Definition: compress_io.h:169
size_t(* read_func)(void *ptr, size_t size, CompressFileHandle *CFH)
Definition: compress_io.h:132
bool(* open_func)(const char *path, int fd, const char *mode, CompressFileHandle *CFH)
Definition: compress_io.h:111
pg_compress_specification compression_spec
Definition: compress_io.h:187
bool(* close_func)(CompressFileHandle *CFH)
Definition: compress_io.h:176
void(* write_func)(const void *ptr, size_t size, CompressFileHandle *CFH)
Definition: compress_io.h:140
void * private_data
Definition: compress_io.h:87
void(* readData)(ArchiveHandle *AH, CompressorState *cs)
Definition: compress_io.h:56
pg_compress_specification compression_spec
Definition: compress_io.h:82
void(* end)(ArchiveHandle *AH, CompressorState *cs)
Definition: compress_io.h:67
ReadFunc readF
Definition: compress_io.h:72
void(* writeData)(ArchiveHandle *AH, CompressorState *cs, const void *data, size_t dLen)
Definition: compress_io.h:61
WriteFunc writeF
Definition: compress_io.h:77
Definition: regguts.h:323