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