Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * compress_zstd.c
4 : : * Routines for archivers to write a Zstd 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_zstd.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres_fe.h"
16 : : #include <unistd.h>
17 : :
18 : : #include "compress_zstd.h"
19 : : #include "pg_backup_utils.h"
20 : :
21 : : #ifndef USE_ZSTD
22 : :
23 : : void
24 : : InitCompressorZstd(CompressorState *cs, const pg_compress_specification compression_spec)
25 : : {
26 : : pg_fatal("this build does not support compression with %s", "ZSTD");
27 : : }
28 : :
29 : : void
30 : : InitCompressFileHandleZstd(CompressFileHandle *CFH, const pg_compress_specification compression_spec)
31 : : {
32 : : pg_fatal("this build does not support compression with %s", "ZSTD");
33 : : }
34 : :
35 : : #else
36 : :
37 : : #include <zstd.h>
38 : :
39 : : typedef struct ZstdCompressorState
40 : : {
41 : : /* This is a normal file to which we read/write compressed data */
42 : : FILE *fp;
43 : :
44 : : ZSTD_CStream *cstream;
45 : : ZSTD_DStream *dstream;
46 : : ZSTD_outBuffer output;
47 : : ZSTD_inBuffer input;
48 : :
49 : : /* pointer to a static string like from strerror(), for Zstd_write() */
50 : : const char *zstderror;
51 : : } ZstdCompressorState;
52 : :
53 : : static ZSTD_CStream *_ZstdCStreamParams(pg_compress_specification compress);
54 : : static void EndCompressorZstd(ArchiveHandle *AH, CompressorState *cs);
55 : : static void WriteDataToArchiveZstd(ArchiveHandle *AH, CompressorState *cs,
56 : : const void *data, size_t dLen);
57 : : static void ReadDataFromArchiveZstd(ArchiveHandle *AH, CompressorState *cs);
58 : :
59 : : static void
936 tomas.vondra@postgre 60 :CBC 8 : _Zstd_CCtx_setParam_or_die(ZSTD_CStream *cstream,
61 : : ZSTD_cParameter param, int value, char *paramname)
62 : : {
63 : : size_t res;
64 : :
65 : 8 : res = ZSTD_CCtx_setParameter(cstream, param, value);
66 [ - + ]: 8 : if (ZSTD_isError(res))
894 alvherre@alvh.no-ip. 67 :UBC 0 : pg_fatal("could not set compression parameter \"%s\": %s",
68 : : paramname, ZSTD_getErrorName(res));
936 tomas.vondra@postgre 69 :CBC 8 : }
70 : :
71 : : /* Return a compression stream with parameters set per argument */
72 : : static ZSTD_CStream *
73 : 7 : _ZstdCStreamParams(pg_compress_specification compress)
74 : : {
75 : : ZSTD_CStream *cstream;
76 : :
77 : 7 : cstream = ZSTD_createCStream();
78 [ - + ]: 7 : if (cstream == NULL)
936 tomas.vondra@postgre 79 :UBC 0 : pg_fatal("could not initialize compression library");
80 : :
936 tomas.vondra@postgre 81 :CBC 7 : _Zstd_CCtx_setParam_or_die(cstream, ZSTD_c_compressionLevel,
82 : : compress.level, "level");
83 : :
935 84 [ + + ]: 7 : if (compress.options & PG_COMPRESSION_OPTION_LONG_DISTANCE)
85 : 1 : _Zstd_CCtx_setParam_or_die(cstream,
86 : : ZSTD_c_enableLongDistanceMatching,
892 tgl@sss.pgh.pa.us 87 : 1 : compress.long_distance, "long");
88 : :
936 tomas.vondra@postgre 89 : 7 : return cstream;
90 : : }
91 : :
92 : : /* Helper function for WriteDataToArchiveZstd and EndCompressorZstd */
93 : : static void
94 : 7 : _ZstdWriteCommon(ArchiveHandle *AH, CompressorState *cs, bool flush)
95 : : {
96 : 7 : ZstdCompressorState *zstdcs = (ZstdCompressorState *) cs->private_data;
97 : 7 : ZSTD_inBuffer *input = &zstdcs->input;
98 : 7 : ZSTD_outBuffer *output = &zstdcs->output;
99 : :
100 : : /* Loop while there's any input or until flushed */
14 tgl@sss.pgh.pa.us 101 [ + + + - ]:GNC 8 : while (input->pos < input->size || flush)
102 : : {
103 : : size_t res;
104 : :
936 tomas.vondra@postgre 105 [ + + ]:CBC 8 : res = ZSTD_compressStream2(zstdcs->cstream, output,
106 : : input, flush ? ZSTD_e_end : ZSTD_e_continue);
107 : :
108 [ - + ]: 8 : if (ZSTD_isError(res))
936 tomas.vondra@postgre 109 :UBC 0 : pg_fatal("could not compress data: %s", ZSTD_getErrorName(res));
110 : :
111 : : /* Dump output buffer if full, or if we're told to flush */
14 tgl@sss.pgh.pa.us 112 [ + + + + ]:GNC 8 : if (output->pos >= output->size || flush)
113 : : {
936 tomas.vondra@postgre 114 :CBC 4 : cs->writeF(AH, output->dst, output->pos);
14 tgl@sss.pgh.pa.us 115 :GNC 4 : output->pos = 0;
116 : : }
117 : :
936 tomas.vondra@postgre 118 [ + + ]:CBC 8 : if (res == 0)
119 : 7 : break; /* End of frame or all input consumed */
120 : : }
121 : 7 : }
122 : :
123 : : static void
124 : 6 : EndCompressorZstd(ArchiveHandle *AH, CompressorState *cs)
125 : : {
126 : 6 : ZstdCompressorState *zstdcs = (ZstdCompressorState *) cs->private_data;
127 : :
128 [ + + ]: 6 : if (cs->readF != NULL)
129 : : {
130 [ - + ]: 3 : Assert(zstdcs->cstream == NULL);
131 : 3 : ZSTD_freeDStream(zstdcs->dstream);
132 : 3 : pg_free(unconstify(void *, zstdcs->input.src));
133 : : }
134 [ + - ]: 3 : else if (cs->writeF != NULL)
135 : : {
136 [ - + ]: 3 : Assert(zstdcs->dstream == NULL);
137 : 3 : _ZstdWriteCommon(AH, cs, true);
138 : 3 : ZSTD_freeCStream(zstdcs->cstream);
139 : : }
140 : :
141 : : /* output buffer may be allocated in either mode */
314 tgl@sss.pgh.pa.us 142 : 6 : pg_free(zstdcs->output.dst);
936 tomas.vondra@postgre 143 : 6 : pg_free(zstdcs);
193 dgustafsson@postgres 144 : 6 : cs->private_data = NULL;
936 tomas.vondra@postgre 145 : 6 : }
146 : :
147 : : static void
148 : 4 : WriteDataToArchiveZstd(ArchiveHandle *AH, CompressorState *cs,
149 : : const void *data, size_t dLen)
150 : : {
151 : 4 : ZstdCompressorState *zstdcs = (ZstdCompressorState *) cs->private_data;
152 : :
153 : 4 : zstdcs->input.src = data;
154 : 4 : zstdcs->input.size = dLen;
155 : 4 : zstdcs->input.pos = 0;
156 : :
157 : 4 : _ZstdWriteCommon(AH, cs, false);
158 : 4 : }
159 : :
160 : : static void
161 : 3 : ReadDataFromArchiveZstd(ArchiveHandle *AH, CompressorState *cs)
162 : : {
163 : 3 : ZstdCompressorState *zstdcs = (ZstdCompressorState *) cs->private_data;
164 : 3 : ZSTD_outBuffer *output = &zstdcs->output;
165 : 3 : ZSTD_inBuffer *input = &zstdcs->input;
166 : 3 : size_t input_allocated_size = ZSTD_DStreamInSize();
167 : : size_t res;
168 : :
169 : : for (;;)
170 : 4 : {
171 : : size_t cnt;
172 : :
173 : : /*
174 : : * Read compressed data. Note that readF can resize the buffer; the
175 : : * new size is tracked and used for future loops.
176 : : */
177 : 7 : input->size = input_allocated_size;
178 : 7 : cnt = cs->readF(AH, (char **) unconstify(void **, &input->src), &input->size);
179 : :
180 : : /* ensure that readF didn't *shrink* the buffer */
181 [ - + ]: 7 : Assert(input->size >= input_allocated_size);
182 : 7 : input_allocated_size = input->size;
183 : 7 : input->size = cnt;
184 : 7 : input->pos = 0;
185 : :
186 [ + + ]: 7 : if (cnt == 0)
187 : 3 : break;
188 : :
189 : : /* Now decompress */
190 [ + + ]: 6 : while (input->pos < input->size)
191 : : {
192 : 5 : output->pos = 0;
193 : 5 : res = ZSTD_decompressStream(zstdcs->dstream, output, input);
194 [ - + ]: 5 : if (ZSTD_isError(res))
936 tomas.vondra@postgre 195 :UBC 0 : pg_fatal("could not decompress data: %s", ZSTD_getErrorName(res));
196 : :
197 : : /*
198 : : * then write the decompressed data to the output handle
199 : : */
936 tomas.vondra@postgre 200 :CBC 5 : ((char *) output->dst)[output->pos] = '\0';
201 : 5 : ahwrite(output->dst, 1, output->pos, AH);
202 : :
203 [ + + ]: 5 : if (res == 0)
204 : 3 : break; /* End of frame */
205 : : }
206 : : }
207 : 3 : }
208 : :
209 : : /* Public routine that supports Zstd compressed data I/O */
210 : : void
211 : 6 : InitCompressorZstd(CompressorState *cs,
212 : : const pg_compress_specification compression_spec)
213 : : {
214 : : ZstdCompressorState *zstdcs;
215 : :
216 : 6 : cs->readData = ReadDataFromArchiveZstd;
217 : 6 : cs->writeData = WriteDataToArchiveZstd;
218 : 6 : cs->end = EndCompressorZstd;
219 : :
220 : 6 : cs->compression_spec = compression_spec;
221 : :
222 : 6 : zstdcs = (ZstdCompressorState *) pg_malloc0(sizeof(*zstdcs));
223 : 6 : cs->private_data = zstdcs;
224 : :
225 : : /* We expect that exactly one of readF/writeF is specified */
226 [ - + ]: 6 : Assert((cs->readF == NULL) != (cs->writeF == NULL));
227 : :
228 [ + + ]: 6 : if (cs->readF != NULL)
229 : : {
230 : 3 : zstdcs->dstream = ZSTD_createDStream();
231 [ - + ]: 3 : if (zstdcs->dstream == NULL)
936 tomas.vondra@postgre 232 :UBC 0 : pg_fatal("could not initialize compression library");
233 : :
936 tomas.vondra@postgre 234 :CBC 3 : zstdcs->input.size = ZSTD_DStreamInSize();
235 : 3 : zstdcs->input.src = pg_malloc(zstdcs->input.size);
236 : :
237 : : /*
238 : : * output.size is the buffer size we tell zstd it can output to.
239 : : * Allocate an additional byte such that ReadDataFromArchiveZstd() can
240 : : * call ahwrite() with a null-terminated string, which is an optimized
241 : : * case in ExecuteSqlCommandBuf().
242 : : */
243 : 3 : zstdcs->output.size = ZSTD_DStreamOutSize();
244 : 3 : zstdcs->output.dst = pg_malloc(zstdcs->output.size + 1);
245 : : }
246 [ + - ]: 3 : else if (cs->writeF != NULL)
247 : : {
248 : 3 : zstdcs->cstream = _ZstdCStreamParams(cs->compression_spec);
249 : :
250 : 3 : zstdcs->output.size = ZSTD_CStreamOutSize();
251 : 3 : zstdcs->output.dst = pg_malloc(zstdcs->output.size);
252 : 3 : zstdcs->output.pos = 0;
253 : : }
254 : 6 : }
255 : :
256 : : /*
257 : : * Compressed stream API
258 : : */
259 : :
260 : : static size_t
59 dgustafsson@postgres 261 : 1761 : Zstd_read_internal(void *ptr, size_t size, CompressFileHandle *CFH, bool exit_on_error)
262 : : {
936 tomas.vondra@postgre 263 : 1761 : ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data;
264 : 1761 : ZSTD_inBuffer *input = &zstdcs->input;
265 : 1761 : ZSTD_outBuffer *output = &zstdcs->output;
266 : 1761 : size_t input_allocated_size = ZSTD_DStreamInSize();
267 : : size_t res,
268 : : cnt;
269 : :
270 : : /*
271 : : * If this is the first call to the reading function, initialize the
272 : : * required datastructures.
273 : : */
59 dgustafsson@postgres 274 [ + + ]: 1761 : if (zstdcs->dstream == NULL)
275 : : {
276 : 5 : zstdcs->input.src = pg_malloc0(input_allocated_size);
277 : 5 : zstdcs->dstream = ZSTD_createDStream();
278 [ - + ]: 5 : if (zstdcs->dstream == NULL)
279 : : {
59 dgustafsson@postgres 280 [ # # ]:UBC 0 : if (exit_on_error)
281 : 0 : pg_fatal("could not initialize compression library");
282 : 0 : return -1;
283 : : }
284 : : }
285 : :
936 tomas.vondra@postgre 286 :CBC 1761 : output->size = size;
287 : 1761 : output->dst = ptr;
288 : 1761 : output->pos = 0;
289 : :
14 tgl@sss.pgh.pa.us 290 [ + + ]:GNC 5263 : while (output->pos < output->size)
291 : : {
936 tomas.vondra@postgre 292 [ - + ]:CBC 1748 : Assert(input->pos <= input->size);
293 [ - + ]: 1748 : Assert(input->size <= input_allocated_size);
294 : :
295 : : /*
296 : : * If the input is completely consumed, start back at the beginning
297 : : */
298 [ + + ]: 1748 : if (input->pos == input->size)
299 : : {
300 : : /* input->size is size produced by "fread" */
301 : 12 : input->size = 0;
302 : : /* input->pos is position consumed by decompress */
303 : 12 : input->pos = 0;
304 : : }
305 : :
306 : : /* read compressed data if we must produce more input */
307 [ + + ]: 1748 : if (input->pos == input->size)
308 : : {
309 : 12 : cnt = fread(unconstify(void *, input->src), 1, input_allocated_size, zstdcs->fp);
59 dgustafsson@postgres 310 [ - + ]: 12 : if (ferror(zstdcs->fp))
311 : : {
59 dgustafsson@postgres 312 [ # # ]:UBC 0 : if (exit_on_error)
313 : 0 : pg_fatal("could not read from input file: %m");
314 : 0 : return -1;
315 : : }
316 : :
936 tomas.vondra@postgre 317 :CBC 12 : input->size = cnt;
318 : :
319 [ - + ]: 12 : Assert(cnt <= input_allocated_size);
320 : :
321 : : /* If we have no more input to consume, we're done */
322 [ + + ]: 12 : if (cnt == 0)
323 : 7 : break;
324 : : }
325 : :
326 [ + - ]: 1741 : while (input->pos < input->size)
327 : : {
328 : : /* now decompress */
329 : 1741 : res = ZSTD_decompressStream(zstdcs->dstream, output, input);
330 : :
331 [ - + ]: 1741 : if (ZSTD_isError(res))
332 : : {
59 dgustafsson@postgres 333 [ # # ]:UBC 0 : if (exit_on_error)
334 : 0 : pg_fatal("could not decompress data: %s", ZSTD_getErrorName(res));
335 : 0 : return -1;
336 : : }
337 : :
936 tomas.vondra@postgre 338 [ + + ]:CBC 1741 : if (output->pos == output->size)
339 : 1738 : break; /* No more room for output */
340 : :
341 [ + - ]: 3 : if (res == 0)
342 : 3 : break; /* End of frame */
343 : : }
344 : : }
345 : :
59 dgustafsson@postgres 346 : 1761 : return output->pos;
347 : : }
348 : :
349 : : static void
936 tomas.vondra@postgre 350 : 93 : Zstd_write(const void *ptr, size_t size, CompressFileHandle *CFH)
351 : : {
352 : 93 : ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data;
353 : 93 : ZSTD_inBuffer *input = &zstdcs->input;
354 : 93 : ZSTD_outBuffer *output = &zstdcs->output;
355 : : size_t res,
356 : : cnt;
357 : :
358 : 93 : input->src = ptr;
359 : 93 : input->size = size;
360 : 93 : input->pos = 0;
361 : :
59 dgustafsson@postgres 362 [ + + ]: 93 : if (zstdcs->cstream == NULL)
363 : : {
364 : 4 : zstdcs->output.size = ZSTD_CStreamOutSize();
14 tgl@sss.pgh.pa.us 365 :GNC 4 : zstdcs->output.dst = pg_malloc(zstdcs->output.size);
366 : 4 : zstdcs->output.pos = 0;
59 dgustafsson@postgres 367 :CBC 4 : zstdcs->cstream = _ZstdCStreamParams(CFH->compression_spec);
368 [ - + ]: 4 : if (zstdcs->cstream == NULL)
59 dgustafsson@postgres 369 :UBC 0 : pg_fatal("could not initialize compression library");
370 : : }
371 : :
372 : : /* Consume all input, to be flushed later */
14 tgl@sss.pgh.pa.us 373 [ + + ]:GNC 279 : while (input->pos < input->size)
374 : : {
936 tomas.vondra@postgre 375 :CBC 93 : res = ZSTD_compressStream2(zstdcs->cstream, output, input, ZSTD_e_continue);
376 [ - + ]: 93 : if (ZSTD_isError(res))
59 dgustafsson@postgres 377 :UBC 0 : pg_fatal("could not write to file: %s", ZSTD_getErrorName(res));
378 : :
379 : : /* Dump output buffer if full */
14 tgl@sss.pgh.pa.us 380 [ - + ]:GNC 93 : if (output->pos >= output->size)
381 : : {
14 tgl@sss.pgh.pa.us 382 :UNC 0 : errno = 0;
383 : 0 : cnt = fwrite(output->dst, 1, output->pos, zstdcs->fp);
384 [ # # ]: 0 : if (cnt != output->pos)
385 : : {
386 [ # # ]: 0 : errno = (errno) ? errno : ENOSPC;
387 : 0 : pg_fatal("could not write to file: %m");
388 : : }
389 : 0 : output->pos = 0;
390 : : }
391 : : }
936 tomas.vondra@postgre 392 :CBC 93 : }
393 : :
394 : : static int
936 tomas.vondra@postgre 395 :GBC 1572 : Zstd_getc(CompressFileHandle *CFH)
396 : : {
397 : : unsigned char ret;
398 : :
59 dgustafsson@postgres 399 [ - + ]: 1572 : if (CFH->read_func(&ret, 1, CFH) != 1)
59 dgustafsson@postgres 400 :UBC 0 : pg_fatal("could not read from input file: end of file");
936 tomas.vondra@postgre 401 :GBC 1572 : return ret;
402 : : }
403 : :
404 : : static char *
936 tomas.vondra@postgre 405 :CBC 2 : Zstd_gets(char *buf, int len, CompressFileHandle *CFH)
406 : : {
407 : : int i;
408 : :
409 [ - + ]: 2 : Assert(len > 0);
410 : :
411 : : /*
412 : : * Read one byte at a time until newline or EOF. This is only used to read
413 : : * the list of LOs, and the I/O is buffered anyway.
414 : : */
415 [ + - ]: 22 : for (i = 0; i < len - 1; ++i)
416 : : {
59 dgustafsson@postgres 417 [ + + ]: 22 : if (Zstd_read_internal(&buf[i], 1, CFH, false) != 1)
936 tomas.vondra@postgre 418 : 1 : break;
419 [ + + ]: 21 : if (buf[i] == '\n')
420 : : {
421 : 1 : ++i;
422 : 1 : break;
423 : : }
424 : : }
425 : 2 : buf[i] = '\0';
426 [ + + ]: 2 : return i > 0 ? buf : NULL;
427 : : }
428 : :
429 : : static size_t
59 dgustafsson@postgres 430 : 1739 : Zstd_read(void *ptr, size_t size, CompressFileHandle *CFH)
431 : : {
432 : 1739 : return Zstd_read_internal(ptr, size, CFH, true);
433 : : }
434 : :
435 : : static bool
936 tomas.vondra@postgre 436 : 9 : Zstd_close(CompressFileHandle *CFH)
437 : : {
438 : 9 : ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data;
59 dgustafsson@postgres 439 : 9 : bool success = true;
440 : :
936 tomas.vondra@postgre 441 [ + + ]: 9 : if (zstdcs->cstream)
442 : : {
443 : : size_t res,
444 : : cnt;
445 : 4 : ZSTD_inBuffer *input = &zstdcs->input;
446 : 4 : ZSTD_outBuffer *output = &zstdcs->output;
447 : :
448 : : /* Loop until the compression buffers are fully consumed */
449 : : for (;;)
450 : : {
451 : 5 : res = ZSTD_compressStream2(zstdcs->cstream, output, input, ZSTD_e_end);
452 [ - + ]: 5 : if (ZSTD_isError(res))
453 : : {
936 tomas.vondra@postgre 454 :UBC 0 : zstdcs->zstderror = ZSTD_getErrorName(res);
59 dgustafsson@postgres 455 : 0 : success = false;
456 : 0 : break;
457 : : }
458 : :
59 dgustafsson@postgres 459 :CBC 5 : errno = 0;
936 tomas.vondra@postgre 460 : 5 : cnt = fwrite(output->dst, 1, output->pos, zstdcs->fp);
461 [ - + ]: 5 : if (cnt != output->pos)
462 : : {
59 dgustafsson@postgres 463 [ # # ]:UBC 0 : errno = (errno) ? errno : ENOSPC;
936 tomas.vondra@postgre 464 : 0 : zstdcs->zstderror = strerror(errno);
59 dgustafsson@postgres 465 : 0 : success = false;
466 : 0 : break;
467 : : }
14 tgl@sss.pgh.pa.us 468 :GNC 5 : output->pos = 0;
469 : :
936 tomas.vondra@postgre 470 [ + + ]:CBC 5 : if (res == 0)
471 : 4 : break; /* End of frame */
472 : : }
473 : :
474 : 4 : ZSTD_freeCStream(zstdcs->cstream);
475 : 4 : pg_free(zstdcs->output.dst);
476 : : }
477 : :
478 [ + + ]: 9 : if (zstdcs->dstream)
479 : : {
480 : 5 : ZSTD_freeDStream(zstdcs->dstream);
481 : 5 : pg_free(unconstify(void *, zstdcs->input.src));
482 : : }
483 : :
59 dgustafsson@postgres 484 : 9 : errno = 0;
936 tomas.vondra@postgre 485 [ - + ]: 9 : if (fclose(zstdcs->fp) != 0)
486 : : {
59 dgustafsson@postgres 487 :UBC 0 : zstdcs->zstderror = strerror(errno);
488 : 0 : success = false;
489 : : }
490 : :
936 tomas.vondra@postgre 491 :CBC 9 : pg_free(zstdcs);
59 dgustafsson@postgres 492 : 9 : CFH->private_data = NULL;
493 : 9 : return success;
494 : : }
495 : :
496 : : static bool
936 tomas.vondra@postgre 497 : 1 : Zstd_eof(CompressFileHandle *CFH)
498 : : {
499 : 1 : ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data;
500 : :
501 : 1 : return feof(zstdcs->fp);
502 : : }
503 : :
504 : : static bool
505 : 9 : Zstd_open(const char *path, int fd, const char *mode,
506 : : CompressFileHandle *CFH)
507 : : {
508 : : FILE *fp;
509 : : ZstdCompressorState *zstdcs;
510 : :
511 : : /*
512 : : * Clear state storage to avoid having the fd point to non-NULL memory on
513 : : * error return.
514 : : */
59 dgustafsson@postgres 515 : 9 : CFH->private_data = NULL;
516 : :
517 : 9 : zstdcs = (ZstdCompressorState *) pg_malloc_extended(sizeof(*zstdcs),
518 : : MCXT_ALLOC_NO_OOM | MCXT_ALLOC_ZERO);
519 [ - + ]: 9 : if (!zstdcs)
520 : : {
59 dgustafsson@postgres 521 :UBC 0 : errno = ENOMEM;
522 : 0 : return false;
523 : : }
524 : :
936 tomas.vondra@postgre 525 [ - + ]:CBC 9 : if (fd >= 0)
59 dgustafsson@postgres 526 :UBC 0 : fp = fdopen(dup(fd), mode);
527 : : else
936 tomas.vondra@postgre 528 :CBC 9 : fp = fopen(path, mode);
529 : :
530 [ - + ]: 9 : if (fp == NULL)
531 : : {
59 dgustafsson@postgres 532 :UBC 0 : pg_free(zstdcs);
936 tomas.vondra@postgre 533 : 0 : return false;
534 : : }
535 : :
936 tomas.vondra@postgre 536 :CBC 9 : zstdcs->fp = fp;
59 dgustafsson@postgres 537 : 9 : CFH->private_data = zstdcs;
538 : :
936 tomas.vondra@postgre 539 : 9 : return true;
540 : : }
541 : :
542 : : static bool
543 : 3 : Zstd_open_write(const char *path, const char *mode, CompressFileHandle *CFH)
544 : : {
545 : : char fname[MAXPGPATH];
546 : :
547 : 3 : sprintf(fname, "%s.zst", path);
548 : 3 : return CFH->open_func(fname, -1, mode, CFH);
549 : : }
550 : :
551 : : static const char *
936 tomas.vondra@postgre 552 :UBC 0 : Zstd_get_error(CompressFileHandle *CFH)
553 : : {
554 : 0 : ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data;
555 : :
556 : 0 : return zstdcs->zstderror;
557 : : }
558 : :
559 : : void
936 tomas.vondra@postgre 560 :CBC 9 : InitCompressFileHandleZstd(CompressFileHandle *CFH,
561 : : const pg_compress_specification compression_spec)
562 : : {
563 : 9 : CFH->open_func = Zstd_open;
564 : 9 : CFH->open_write_func = Zstd_open_write;
565 : 9 : CFH->read_func = Zstd_read;
566 : 9 : CFH->write_func = Zstd_write;
567 : 9 : CFH->gets_func = Zstd_gets;
568 : 9 : CFH->getc_func = Zstd_getc;
569 : 9 : CFH->close_func = Zstd_close;
570 : 9 : CFH->eof_func = Zstd_eof;
571 : 9 : CFH->get_error_func = Zstd_get_error;
572 : :
573 : 9 : CFH->compression_spec = compression_spec;
574 : :
575 : 9 : CFH->private_data = NULL;
576 : 9 : }
577 : :
578 : : #endif /* USE_ZSTD */
|