1 /*-------------------------------------------------------------------------
2 *
3 * pg_backup_directory.c
4 *
5 * A directory format dump is a directory, which contains a "toc.dat" file
6 * for the TOC, and a separate file for each data entry, named "<oid>.dat".
7 * Large objects (BLOBs) are stored in separate files named "blob_<uid>.dat",
8 * and there's a plain-text TOC file for them called "blobs.toc". If
9 * compression is used, each data file is individually compressed and the
10 * ".gz" suffix is added to the filenames. The TOC files are never
11 * compressed by pg_dump, however they are accepted with the .gz suffix too,
12 * in case the user has manually compressed them with 'gzip'.
13 *
14 * NOTE: This format is identical to the files written in the tar file in
15 * the 'tar' format, except that we don't write the restore.sql file (TODO),
16 * and the tar format doesn't support compression. Please keep the formats in
17 * sync.
18 *
19 *
20 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
21 * Portions Copyright (c) 1994, Regents of the University of California
22 * Portions Copyright (c) 2000, Philip Warner
23 *
24 * Rights are granted to use this software in any way so long
25 * as this notice is not removed.
26 *
27 * The author is not responsible for loss or damages that may
28 * result from it's use.
29 *
30 * IDENTIFICATION
31 * src/bin/pg_dump/pg_backup_directory.c
32 *
33 *-------------------------------------------------------------------------
34 */
35 #include "postgres_fe.h"
36
37 #include "compress_io.h"
38 #include "parallel.h"
39 #include "pg_backup_utils.h"
40 #include "common/file_utils.h"
41
42 #include <dirent.h>
43 #include <sys/stat.h>
44
45 typedef struct
46 {
47 /*
48 * Our archive location. This is basically what the user specified as his
49 * backup file but of course here it is a directory.
50 */
51 char *directory;
52
53 cfp *dataFH; /* currently open data file */
54
55 cfp *blobsTocFH; /* file handle for blobs.toc */
56 ParallelState *pstate; /* for parallel backup / restore */
57 } lclContext;
58
59 typedef struct
60 {
61 char *filename; /* filename excluding the directory (basename) */
62 } lclTocEntry;
63
64 /* translator: this is a module name */
65 static const char *modulename = gettext_noop("directory archiver");
66
67 /* prototypes for private functions */
68 static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
69 static void _StartData(ArchiveHandle *AH, TocEntry *te);
70 static void _EndData(ArchiveHandle *AH, TocEntry *te);
71 static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
72 static int _WriteByte(ArchiveHandle *AH, const int i);
73 static int _ReadByte(ArchiveHandle *);
74 static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
75 static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len);
76 static void _CloseArchive(ArchiveHandle *AH);
77 static void _ReopenArchive(ArchiveHandle *AH);
78 static void _PrintTocData(ArchiveHandle *AH, TocEntry *te);
79
80 static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
81 static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
82 static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
83
84 static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
85 static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
86 static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
87 static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
88 static void _LoadBlobs(ArchiveHandle *AH);
89
90 static void _Clone(ArchiveHandle *AH);
91 static void _DeClone(ArchiveHandle *AH);
92
93 static int _WorkerJobRestoreDirectory(ArchiveHandle *AH, TocEntry *te);
94 static int _WorkerJobDumpDirectory(ArchiveHandle *AH, TocEntry *te);
95
96 static void setFilePath(ArchiveHandle *AH, char *buf,
97 const char *relativeFilename);
98
99 /*
100 * Init routine required by ALL formats. This is a global routine
101 * and should be declared in pg_backup_archiver.h
102 *
103 * Its task is to create any extra archive context (using AH->formatData),
104 * and to initialize the supported function pointers.
105 *
106 * It should also prepare whatever its input source is for reading/writing,
107 * and in the case of a read mode connection, it should load the Header & TOC.
108 */
109 void
InitArchiveFmt_Directory(ArchiveHandle * AH)110 InitArchiveFmt_Directory(ArchiveHandle *AH)
111 {
112 lclContext *ctx;
113
114 /* Assuming static functions, this can be copied for each format. */
115 AH->ArchiveEntryPtr = _ArchiveEntry;
116 AH->StartDataPtr = _StartData;
117 AH->WriteDataPtr = _WriteData;
118 AH->EndDataPtr = _EndData;
119 AH->WriteBytePtr = _WriteByte;
120 AH->ReadBytePtr = _ReadByte;
121 AH->WriteBufPtr = _WriteBuf;
122 AH->ReadBufPtr = _ReadBuf;
123 AH->ClosePtr = _CloseArchive;
124 AH->ReopenPtr = _ReopenArchive;
125 AH->PrintTocDataPtr = _PrintTocData;
126 AH->ReadExtraTocPtr = _ReadExtraToc;
127 AH->WriteExtraTocPtr = _WriteExtraToc;
128 AH->PrintExtraTocPtr = _PrintExtraToc;
129
130 AH->StartBlobsPtr = _StartBlobs;
131 AH->StartBlobPtr = _StartBlob;
132 AH->EndBlobPtr = _EndBlob;
133 AH->EndBlobsPtr = _EndBlobs;
134
135 AH->ClonePtr = _Clone;
136 AH->DeClonePtr = _DeClone;
137
138 AH->WorkerJobRestorePtr = _WorkerJobRestoreDirectory;
139 AH->WorkerJobDumpPtr = _WorkerJobDumpDirectory;
140
141 /* Set up our private context */
142 ctx = (lclContext *) pg_malloc0(sizeof(lclContext));
143 AH->formatData = (void *) ctx;
144
145 ctx->dataFH = NULL;
146 ctx->blobsTocFH = NULL;
147
148 /* Initialize LO buffering */
149 AH->lo_buf_size = LOBBUFSIZE;
150 AH->lo_buf = (void *) pg_malloc(LOBBUFSIZE);
151
152 /*
153 * Now open the TOC file
154 */
155
156 if (!AH->fSpec || strcmp(AH->fSpec, "") == 0)
157 exit_horribly(modulename, "no output directory specified\n");
158
159 ctx->directory = AH->fSpec;
160
161 if (AH->mode == archModeWrite)
162 {
163 struct stat st;
164 bool is_empty = false;
165
166 /* we accept an empty existing directory */
167 if (stat(ctx->directory, &st) == 0 && S_ISDIR(st.st_mode))
168 {
169 DIR *dir = opendir(ctx->directory);
170
171 if (dir)
172 {
173 struct dirent *d;
174
175 is_empty = true;
176 while (errno = 0, (d = readdir(dir)))
177 {
178 if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0)
179 {
180 is_empty = false;
181 break;
182 }
183 }
184
185 if (errno)
186 exit_horribly(modulename, "could not read directory \"%s\": %s\n",
187 ctx->directory, strerror(errno));
188
189 if (closedir(dir))
190 exit_horribly(modulename, "could not close directory \"%s\": %s\n",
191 ctx->directory, strerror(errno));
192 }
193 }
194
195 if (!is_empty && mkdir(ctx->directory, 0700) < 0)
196 exit_horribly(modulename, "could not create directory \"%s\": %s\n",
197 ctx->directory, strerror(errno));
198 }
199 else
200 { /* Read Mode */
201 char fname[MAXPGPATH];
202 cfp *tocFH;
203
204 setFilePath(AH, fname, "toc.dat");
205
206 tocFH = cfopen_read(fname, PG_BINARY_R);
207 if (tocFH == NULL)
208 exit_horribly(modulename,
209 "could not open input file \"%s\": %s\n",
210 fname, strerror(errno));
211
212 ctx->dataFH = tocFH;
213
214 /*
215 * The TOC of a directory format dump shares the format code of the
216 * tar format.
217 */
218 AH->format = archTar;
219 ReadHead(AH);
220 AH->format = archDirectory;
221 ReadToc(AH);
222
223 /* Nothing else in the file, so close it again... */
224 if (cfclose(tocFH) != 0)
225 exit_horribly(modulename, "could not close TOC file: %s\n",
226 strerror(errno));
227 ctx->dataFH = NULL;
228 }
229 }
230
231 /*
232 * Called by the Archiver when the dumper creates a new TOC entry.
233 *
234 * We determine the filename for this entry.
235 */
236 static void
_ArchiveEntry(ArchiveHandle * AH,TocEntry * te)237 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
238 {
239 lclTocEntry *tctx;
240 char fn[MAXPGPATH];
241
242 tctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
243 if (te->dataDumper)
244 {
245 snprintf(fn, MAXPGPATH, "%d.dat", te->dumpId);
246 tctx->filename = pg_strdup(fn);
247 }
248 else if (strcmp(te->desc, "BLOBS") == 0)
249 tctx->filename = pg_strdup("blobs.toc");
250 else
251 tctx->filename = NULL;
252
253 te->formatData = (void *) tctx;
254 }
255
256 /*
257 * Called by the Archiver to save any extra format-related TOC entry
258 * data.
259 *
260 * Use the Archiver routines to write data - they are non-endian, and
261 * maintain other important file information.
262 */
263 static void
_WriteExtraToc(ArchiveHandle * AH,TocEntry * te)264 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
265 {
266 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
267
268 /*
269 * A dumpable object has set tctx->filename, any other object has not.
270 * (see _ArchiveEntry).
271 */
272 if (tctx->filename)
273 WriteStr(AH, tctx->filename);
274 else
275 WriteStr(AH, "");
276 }
277
278 /*
279 * Called by the Archiver to read any extra format-related TOC data.
280 *
281 * Needs to match the order defined in _WriteExtraToc, and should also
282 * use the Archiver input routines.
283 */
284 static void
_ReadExtraToc(ArchiveHandle * AH,TocEntry * te)285 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
286 {
287 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
288
289 if (tctx == NULL)
290 {
291 tctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
292 te->formatData = (void *) tctx;
293 }
294
295 tctx->filename = ReadStr(AH);
296 if (strlen(tctx->filename) == 0)
297 {
298 free(tctx->filename);
299 tctx->filename = NULL;
300 }
301 }
302
303 /*
304 * Called by the Archiver when restoring an archive to output a comment
305 * that includes useful information about the TOC entry.
306 */
307 static void
_PrintExtraToc(ArchiveHandle * AH,TocEntry * te)308 _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
309 {
310 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
311
312 if (AH->public.verbose && tctx->filename)
313 ahprintf(AH, "-- File: %s\n", tctx->filename);
314 }
315
316 /*
317 * Called by the archiver when saving TABLE DATA (not schema). This routine
318 * should save whatever format-specific information is needed to read
319 * the archive back.
320 *
321 * It is called just prior to the dumper's 'DataDumper' routine being called.
322 *
323 * We create the data file for writing.
324 */
325 static void
_StartData(ArchiveHandle * AH,TocEntry * te)326 _StartData(ArchiveHandle *AH, TocEntry *te)
327 {
328 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
329 lclContext *ctx = (lclContext *) AH->formatData;
330 char fname[MAXPGPATH];
331
332 setFilePath(AH, fname, tctx->filename);
333
334 ctx->dataFH = cfopen_write(fname, PG_BINARY_W, AH->compression);
335 if (ctx->dataFH == NULL)
336 exit_horribly(modulename, "could not open output file \"%s\": %s\n",
337 fname, strerror(errno));
338 }
339
340 /*
341 * Called by archiver when dumper calls WriteData. This routine is
342 * called for both BLOB and TABLE data; it is the responsibility of
343 * the format to manage each kind of data using StartBlob/StartData.
344 *
345 * It should only be called from within a DataDumper routine.
346 *
347 * We write the data to the open data file.
348 */
349 static void
_WriteData(ArchiveHandle * AH,const void * data,size_t dLen)350 _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
351 {
352 lclContext *ctx = (lclContext *) AH->formatData;
353
354 errno = 0;
355 if (dLen > 0 && cfwrite(data, dLen, ctx->dataFH) != dLen)
356 {
357 /* if write didn't set errno, assume problem is no disk space */
358 if (errno == 0)
359 errno = ENOSPC;
360 exit_horribly(modulename, "could not write to output file: %s\n",
361 get_cfp_error(ctx->dataFH));
362 }
363
364 return;
365 }
366
367 /*
368 * Called by the archiver when a dumper's 'DataDumper' routine has
369 * finished.
370 *
371 * We close the data file.
372 */
373 static void
_EndData(ArchiveHandle * AH,TocEntry * te)374 _EndData(ArchiveHandle *AH, TocEntry *te)
375 {
376 lclContext *ctx = (lclContext *) AH->formatData;
377
378 /* Close the file */
379 cfclose(ctx->dataFH);
380
381 ctx->dataFH = NULL;
382 }
383
384 /*
385 * Print data for a given file (can be a BLOB as well)
386 */
387 static void
_PrintFileData(ArchiveHandle * AH,char * filename)388 _PrintFileData(ArchiveHandle *AH, char *filename)
389 {
390 size_t cnt;
391 char *buf;
392 size_t buflen;
393 cfp *cfp;
394
395 if (!filename)
396 return;
397
398 cfp = cfopen_read(filename, PG_BINARY_R);
399
400 if (!cfp)
401 exit_horribly(modulename, "could not open input file \"%s\": %s\n",
402 filename, strerror(errno));
403
404 buf = pg_malloc(ZLIB_OUT_SIZE);
405 buflen = ZLIB_OUT_SIZE;
406
407 while ((cnt = cfread(buf, buflen, cfp)))
408 {
409 ahwrite(buf, 1, cnt, AH);
410 }
411
412 free(buf);
413 if (cfclose(cfp) !=0)
414 exit_horribly(modulename, "could not close data file \"%s\": %s\n",
415 filename, strerror(errno));
416 }
417
418 /*
419 * Print data for a given TOC entry
420 */
421 static void
_PrintTocData(ArchiveHandle * AH,TocEntry * te)422 _PrintTocData(ArchiveHandle *AH, TocEntry *te)
423 {
424 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
425
426 if (!tctx->filename)
427 return;
428
429 if (strcmp(te->desc, "BLOBS") == 0)
430 _LoadBlobs(AH);
431 else
432 {
433 char fname[MAXPGPATH];
434
435 setFilePath(AH, fname, tctx->filename);
436 _PrintFileData(AH, fname);
437 }
438 }
439
440 static void
_LoadBlobs(ArchiveHandle * AH)441 _LoadBlobs(ArchiveHandle *AH)
442 {
443 Oid oid;
444 lclContext *ctx = (lclContext *) AH->formatData;
445 char tocfname[MAXPGPATH];
446 char line[MAXPGPATH];
447
448 StartRestoreBlobs(AH);
449
450 setFilePath(AH, tocfname, "blobs.toc");
451
452 ctx->blobsTocFH = cfopen_read(tocfname, PG_BINARY_R);
453
454 if (ctx->blobsTocFH == NULL)
455 exit_horribly(modulename, "could not open large object TOC file \"%s\" for input: %s\n",
456 tocfname, strerror(errno));
457
458 /* Read the blobs TOC file line-by-line, and process each blob */
459 while ((cfgets(ctx->blobsTocFH, line, MAXPGPATH)) != NULL)
460 {
461 char blobfname[MAXPGPATH + 1];
462 char path[MAXPGPATH];
463
464 /* Can't overflow because line and blobfname are the same length. */
465 if (sscanf(line, "%u %" CppAsString2(MAXPGPATH) "s\n", &oid, blobfname) != 2)
466 exit_horribly(modulename, "invalid line in large object TOC file \"%s\": \"%s\"\n",
467 tocfname, line);
468
469 StartRestoreBlob(AH, oid, AH->public.ropt->dropSchema);
470 snprintf(path, MAXPGPATH, "%s/%s", ctx->directory, blobfname);
471 _PrintFileData(AH, path);
472 EndRestoreBlob(AH, oid);
473 }
474 if (!cfeof(ctx->blobsTocFH))
475 exit_horribly(modulename, "error reading large object TOC file \"%s\"\n",
476 tocfname);
477
478 if (cfclose(ctx->blobsTocFH) != 0)
479 exit_horribly(modulename, "could not close large object TOC file \"%s\": %s\n",
480 tocfname, strerror(errno));
481
482 ctx->blobsTocFH = NULL;
483
484 EndRestoreBlobs(AH);
485 }
486
487
488 /*
489 * Write a byte of data to the archive.
490 * Called by the archiver to do integer & byte output to the archive.
491 * These routines are only used to read & write the headers & TOC.
492 */
493 static int
_WriteByte(ArchiveHandle * AH,const int i)494 _WriteByte(ArchiveHandle *AH, const int i)
495 {
496 unsigned char c = (unsigned char) i;
497 lclContext *ctx = (lclContext *) AH->formatData;
498
499 errno = 0;
500 if (cfwrite(&c, 1, ctx->dataFH) != 1)
501 {
502 /* if write didn't set errno, assume problem is no disk space */
503 if (errno == 0)
504 errno = ENOSPC;
505 exit_horribly(modulename, "could not write to output file: %s\n",
506 get_cfp_error(ctx->dataFH));
507 }
508
509 return 1;
510 }
511
512 /*
513 * Read a byte of data from the archive.
514 * Called by the archiver to read bytes & integers from the archive.
515 * These routines are only used to read & write headers & TOC.
516 * EOF should be treated as a fatal error.
517 */
518 static int
_ReadByte(ArchiveHandle * AH)519 _ReadByte(ArchiveHandle *AH)
520 {
521 lclContext *ctx = (lclContext *) AH->formatData;
522
523 return cfgetc(ctx->dataFH);
524 }
525
526 /*
527 * Write a buffer of data to the archive.
528 * Called by the archiver to write a block of bytes to the TOC or a data file.
529 */
530 static void
_WriteBuf(ArchiveHandle * AH,const void * buf,size_t len)531 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
532 {
533 lclContext *ctx = (lclContext *) AH->formatData;
534
535 errno = 0;
536 if (cfwrite(buf, len, ctx->dataFH) != len)
537 {
538 /* if write didn't set errno, assume problem is no disk space */
539 if (errno == 0)
540 errno = ENOSPC;
541 exit_horribly(modulename, "could not write to output file: %s\n",
542 get_cfp_error(ctx->dataFH));
543 }
544
545 return;
546 }
547
548 /*
549 * Read a block of bytes from the archive.
550 *
551 * Called by the archiver to read a block of bytes from the archive
552 */
553 static void
_ReadBuf(ArchiveHandle * AH,void * buf,size_t len)554 _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
555 {
556 lclContext *ctx = (lclContext *) AH->formatData;
557
558 /*
559 * If there was an I/O error, we already exited in cfread(), so here we
560 * exit on short reads.
561 */
562 if (cfread(buf, len, ctx->dataFH) != len)
563 exit_horribly(modulename,
564 "could not read from input file: end of file\n");
565
566 return;
567 }
568
569 /*
570 * Close the archive.
571 *
572 * When writing the archive, this is the routine that actually starts
573 * the process of saving it to files. No data should be written prior
574 * to this point, since the user could sort the TOC after creating it.
575 *
576 * If an archive is to be written, this routine must call:
577 * WriteHead to save the archive header
578 * WriteToc to save the TOC entries
579 * WriteDataChunks to save all DATA & BLOBs.
580 */
581 static void
_CloseArchive(ArchiveHandle * AH)582 _CloseArchive(ArchiveHandle *AH)
583 {
584 lclContext *ctx = (lclContext *) AH->formatData;
585
586 if (AH->mode == archModeWrite)
587 {
588 cfp *tocFH;
589 char fname[MAXPGPATH];
590
591 setFilePath(AH, fname, "toc.dat");
592
593 /* this will actually fork the processes for a parallel backup */
594 ctx->pstate = ParallelBackupStart(AH);
595
596 /* The TOC is always created uncompressed */
597 tocFH = cfopen_write(fname, PG_BINARY_W, 0);
598 if (tocFH == NULL)
599 exit_horribly(modulename, "could not open output file \"%s\": %s\n",
600 fname, strerror(errno));
601 ctx->dataFH = tocFH;
602
603 /*
604 * Write 'tar' in the format field of the toc.dat file. The directory
605 * is compatible with 'tar', so there's no point having a different
606 * format code for it.
607 */
608 AH->format = archTar;
609 WriteHead(AH);
610 AH->format = archDirectory;
611 WriteToc(AH);
612 if (cfclose(tocFH) != 0)
613 exit_horribly(modulename, "could not close TOC file: %s\n",
614 strerror(errno));
615 WriteDataChunks(AH, ctx->pstate);
616
617 ParallelBackupEnd(AH, ctx->pstate);
618
619 /*
620 * In directory mode, there is no need to sync all the entries
621 * individually. Just recurse once through all the files generated.
622 */
623 if (AH->dosync)
624 fsync_dir_recurse(ctx->directory, progname);
625 }
626 AH->FH = NULL;
627 }
628
629 /*
630 * Reopen the archive's file handle.
631 */
632 static void
_ReopenArchive(ArchiveHandle * AH)633 _ReopenArchive(ArchiveHandle *AH)
634 {
635 /*
636 * Our TOC is in memory, our data files are opened by each child anyway as
637 * they are separate. We support reopening the archive by just doing
638 * nothing.
639 */
640 }
641
642 /*
643 * BLOB support
644 */
645
646 /*
647 * Called by the archiver when starting to save all BLOB DATA (not schema).
648 * It is called just prior to the dumper's DataDumper routine.
649 *
650 * We open the large object TOC file here, so that we can append a line to
651 * it for each blob.
652 */
653 static void
_StartBlobs(ArchiveHandle * AH,TocEntry * te)654 _StartBlobs(ArchiveHandle *AH, TocEntry *te)
655 {
656 lclContext *ctx = (lclContext *) AH->formatData;
657 char fname[MAXPGPATH];
658
659 setFilePath(AH, fname, "blobs.toc");
660
661 /* The blob TOC file is never compressed */
662 ctx->blobsTocFH = cfopen_write(fname, "ab", 0);
663 if (ctx->blobsTocFH == NULL)
664 exit_horribly(modulename, "could not open output file \"%s\": %s\n",
665 fname, strerror(errno));
666 }
667
668 /*
669 * Called by the archiver when we're about to start dumping a blob.
670 *
671 * We create a file to write the blob to.
672 */
673 static void
_StartBlob(ArchiveHandle * AH,TocEntry * te,Oid oid)674 _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
675 {
676 lclContext *ctx = (lclContext *) AH->formatData;
677 char fname[MAXPGPATH];
678
679 snprintf(fname, MAXPGPATH, "%s/blob_%u.dat", ctx->directory, oid);
680
681 ctx->dataFH = cfopen_write(fname, PG_BINARY_W, AH->compression);
682
683 if (ctx->dataFH == NULL)
684 exit_horribly(modulename, "could not open output file \"%s\": %s\n",
685 fname, strerror(errno));
686 }
687
688 /*
689 * Called by the archiver when the dumper is finished writing a blob.
690 *
691 * We close the blob file and write an entry to the blob TOC file for it.
692 */
693 static void
_EndBlob(ArchiveHandle * AH,TocEntry * te,Oid oid)694 _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
695 {
696 lclContext *ctx = (lclContext *) AH->formatData;
697 char buf[50];
698 int len;
699
700 /* Close the BLOB data file itself */
701 cfclose(ctx->dataFH);
702 ctx->dataFH = NULL;
703
704 /* register the blob in blobs.toc */
705 len = snprintf(buf, sizeof(buf), "%u blob_%u.dat\n", oid, oid);
706 if (cfwrite(buf, len, ctx->blobsTocFH) != len)
707 exit_horribly(modulename, "could not write to blobs TOC file\n");
708 }
709
710 /*
711 * Called by the archiver when finishing saving all BLOB DATA.
712 *
713 * We close the blobs TOC file.
714 */
715 static void
_EndBlobs(ArchiveHandle * AH,TocEntry * te)716 _EndBlobs(ArchiveHandle *AH, TocEntry *te)
717 {
718 lclContext *ctx = (lclContext *) AH->formatData;
719
720 cfclose(ctx->blobsTocFH);
721 ctx->blobsTocFH = NULL;
722 }
723
724 /*
725 * Gets a relative file name and prepends the output directory, writing the
726 * result to buf. The caller needs to make sure that buf is MAXPGPATH bytes
727 * big. Can't use a static char[MAXPGPATH] inside the function because we run
728 * multithreaded on Windows.
729 */
730 static void
setFilePath(ArchiveHandle * AH,char * buf,const char * relativeFilename)731 setFilePath(ArchiveHandle *AH, char *buf, const char *relativeFilename)
732 {
733 lclContext *ctx = (lclContext *) AH->formatData;
734 char *dname;
735
736 dname = ctx->directory;
737
738 if (strlen(dname) + 1 + strlen(relativeFilename) + 1 > MAXPGPATH)
739 exit_horribly(modulename, "file name too long: \"%s\"\n", dname);
740
741 strcpy(buf, dname);
742 strcat(buf, "/");
743 strcat(buf, relativeFilename);
744 }
745
746 /*
747 * Clone format-specific fields during parallel restoration.
748 */
749 static void
_Clone(ArchiveHandle * AH)750 _Clone(ArchiveHandle *AH)
751 {
752 lclContext *ctx = (lclContext *) AH->formatData;
753
754 AH->formatData = (lclContext *) pg_malloc(sizeof(lclContext));
755 memcpy(AH->formatData, ctx, sizeof(lclContext));
756 ctx = (lclContext *) AH->formatData;
757
758 /*
759 * Note: we do not make a local lo_buf because we expect at most one BLOBS
760 * entry per archive, so no parallelism is possible. Likewise,
761 * TOC-entry-local state isn't an issue because any one TOC entry is
762 * touched by just one worker child.
763 */
764
765 /*
766 * We also don't copy the ParallelState pointer (pstate), only the master
767 * process ever writes to it.
768 */
769 }
770
771 static void
_DeClone(ArchiveHandle * AH)772 _DeClone(ArchiveHandle *AH)
773 {
774 lclContext *ctx = (lclContext *) AH->formatData;
775
776 free(ctx);
777 }
778
779 /*
780 * This function is executed in the child of a parallel backup for a
781 * directory-format archive and dumps the actual data for one TOC entry.
782 */
783 static int
_WorkerJobDumpDirectory(ArchiveHandle * AH,TocEntry * te)784 _WorkerJobDumpDirectory(ArchiveHandle *AH, TocEntry *te)
785 {
786 /*
787 * This function returns void. We either fail and die horribly or
788 * succeed... A failure will be detected by the parent when the child dies
789 * unexpectedly.
790 */
791 WriteDataChunksForTocEntry(AH, te);
792
793 return 0;
794 }
795
796 /*
797 * This function is executed in the child of a parallel restore from a
798 * directory-format archive and restores the actual data for one TOC entry.
799 */
800 static int
_WorkerJobRestoreDirectory(ArchiveHandle * AH,TocEntry * te)801 _WorkerJobRestoreDirectory(ArchiveHandle *AH, TocEntry *te)
802 {
803 return parallel_restore(AH, te);
804 }
805