]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_backup_directory.c
pg_dump: Add missing newlines at end of messages
[postgresql] / src / bin / pg_dump / pg_backup_directory.c
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-2012, 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
36 #include "compress_io.h"
37 #include "dumpmem.h"
38 #include "dumputils.h"
39
40 #include <dirent.h>
41 #include <sys/stat.h>
42
43 typedef struct
44 {
45         /*
46          * Our archive location. This is basically what the user specified as his
47          * backup file but of course here it is a directory.
48          */
49         char       *directory;
50
51         cfp                *dataFH;                     /* currently open data file */
52
53         cfp                *blobsTocFH;         /* file handle for blobs.toc */
54 } lclContext;
55
56 typedef struct
57 {
58         char       *filename;           /* filename excluding the directory (basename) */
59 } lclTocEntry;
60
61 static const char *modulename = gettext_noop("directory archiver");
62
63 /* prototypes for private functions */
64 static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
65 static void _StartData(ArchiveHandle *AH, TocEntry *te);
66 static void _EndData(ArchiveHandle *AH, TocEntry *te);
67 static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
68 static int      _WriteByte(ArchiveHandle *AH, const int i);
69 static int      _ReadByte(ArchiveHandle *);
70 static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
71 static size_t _ReadBuf(ArchiveHandle *AH, void *buf, size_t len);
72 static void _CloseArchive(ArchiveHandle *AH);
73 static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
74
75 static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
76 static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
77 static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
78
79 static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
80 static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
81 static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
82 static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
83 static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);
84
85 static char *prependDirectory(ArchiveHandle *AH, const char *relativeFilename);
86
87 static void createDirectory(const char *dir);
88
89
90 /*
91  *      Init routine required by ALL formats. This is a global routine
92  *      and should be declared in pg_backup_archiver.h
93  *
94  *      Its task is to create any extra archive context (using AH->formatData),
95  *      and to initialize the supported function pointers.
96  *
97  *      It should also prepare whatever its input source is for reading/writing,
98  *      and in the case of a read mode connection, it should load the Header & TOC.
99  */
100 void
101 InitArchiveFmt_Directory(ArchiveHandle *AH)
102 {
103         lclContext *ctx;
104
105         /* Assuming static functions, this can be copied for each format. */
106         AH->ArchiveEntryPtr = _ArchiveEntry;
107         AH->StartDataPtr = _StartData;
108         AH->WriteDataPtr = _WriteData;
109         AH->EndDataPtr = _EndData;
110         AH->WriteBytePtr = _WriteByte;
111         AH->ReadBytePtr = _ReadByte;
112         AH->WriteBufPtr = _WriteBuf;
113         AH->ReadBufPtr = _ReadBuf;
114         AH->ClosePtr = _CloseArchive;
115         AH->ReopenPtr = NULL;
116         AH->PrintTocDataPtr = _PrintTocData;
117         AH->ReadExtraTocPtr = _ReadExtraToc;
118         AH->WriteExtraTocPtr = _WriteExtraToc;
119         AH->PrintExtraTocPtr = _PrintExtraToc;
120
121         AH->StartBlobsPtr = _StartBlobs;
122         AH->StartBlobPtr = _StartBlob;
123         AH->EndBlobPtr = _EndBlob;
124         AH->EndBlobsPtr = _EndBlobs;
125
126         AH->ClonePtr = NULL;
127         AH->DeClonePtr = NULL;
128
129         /* Set up our private context */
130         ctx = (lclContext *) pg_calloc(1, sizeof(lclContext));
131         AH->formatData = (void *) ctx;
132
133         ctx->dataFH = NULL;
134         ctx->blobsTocFH = NULL;
135
136         /* Initialize LO buffering */
137         AH->lo_buf_size = LOBBUFSIZE;
138         AH->lo_buf = (void *) pg_malloc(LOBBUFSIZE);
139
140         /*
141          * Now open the TOC file
142          */
143
144         if (!AH->fSpec || strcmp(AH->fSpec, "") == 0)
145                 exit_horribly(modulename, "no output directory specified\n");
146
147         ctx->directory = AH->fSpec;
148
149         if (AH->mode == archModeWrite)
150         {
151                 /* Create the directory, errors are caught there */
152                 createDirectory(ctx->directory);
153         }
154         else
155         {                                                       /* Read Mode */
156                 char       *fname;
157                 cfp                *tocFH;
158
159                 fname = prependDirectory(AH, "toc.dat");
160
161                 tocFH = cfopen_read(fname, PG_BINARY_R);
162                 if (tocFH == NULL)
163                         exit_horribly(modulename,
164                                                   "could not open input file \"%s\": %s\n",
165                                                   fname, strerror(errno));
166
167                 ctx->dataFH = tocFH;
168
169                 /*
170                  * The TOC of a directory format dump shares the format code of the
171                  * tar format.
172                  */
173                 AH->format = archTar;
174                 ReadHead(AH);
175                 AH->format = archDirectory;
176                 ReadToc(AH);
177
178                 /* Nothing else in the file, so close it again... */
179                 if (cfclose(tocFH) != 0)
180                         exit_horribly(modulename, "could not close TOC file: %s\n",
181                                                   strerror(errno));
182                 ctx->dataFH = NULL;
183         }
184 }
185
186 /*
187  * Called by the Archiver when the dumper creates a new TOC entry.
188  *
189  * We determine the filename for this entry.
190 */
191 static void
192 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
193 {
194         lclTocEntry *tctx;
195         char            fn[MAXPGPATH];
196
197         tctx = (lclTocEntry *) pg_calloc(1, sizeof(lclTocEntry));
198         if (te->dataDumper)
199         {
200                 snprintf(fn, MAXPGPATH, "%d.dat", te->dumpId);
201                 tctx->filename = pg_strdup(fn);
202         }
203         else if (strcmp(te->desc, "BLOBS") == 0)
204                 tctx->filename = pg_strdup("blobs.toc");
205         else
206                 tctx->filename = NULL;
207
208         te->formatData = (void *) tctx;
209 }
210
211 /*
212  * Called by the Archiver to save any extra format-related TOC entry
213  * data.
214  *
215  * Use the Archiver routines to write data - they are non-endian, and
216  * maintain other important file information.
217  */
218 static void
219 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
220 {
221         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
222
223         /*
224          * A dumpable object has set tctx->filename, any other object has not.
225          * (see _ArchiveEntry).
226          */
227         if (tctx->filename)
228                 WriteStr(AH, tctx->filename);
229         else
230                 WriteStr(AH, "");
231 }
232
233 /*
234  * Called by the Archiver to read any extra format-related TOC data.
235  *
236  * Needs to match the order defined in _WriteExtraToc, and should also
237  * use the Archiver input routines.
238  */
239 static void
240 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
241 {
242         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
243
244         if (tctx == NULL)
245         {
246                 tctx = (lclTocEntry *) pg_calloc(1, sizeof(lclTocEntry));
247                 te->formatData = (void *) tctx;
248         }
249
250         tctx->filename = ReadStr(AH);
251         if (strlen(tctx->filename) == 0)
252         {
253                 free(tctx->filename);
254                 tctx->filename = NULL;
255         }
256 }
257
258 /*
259  * Called by the Archiver when restoring an archive to output a comment
260  * that includes useful information about the TOC entry.
261  */
262 static void
263 _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
264 {
265         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
266
267         if (AH->public.verbose && tctx->filename)
268                 ahprintf(AH, "-- File: %s\n", tctx->filename);
269 }
270
271 /*
272  * Called by the archiver when saving TABLE DATA (not schema). This routine
273  * should save whatever format-specific information is needed to read
274  * the archive back.
275  *
276  * It is called just prior to the dumper's 'DataDumper' routine being called.
277  *
278  * We create the data file for writing.
279  */
280 static void
281 _StartData(ArchiveHandle *AH, TocEntry *te)
282 {
283         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
284         lclContext *ctx = (lclContext *) AH->formatData;
285         char       *fname;
286
287         fname = prependDirectory(AH, tctx->filename);
288
289         ctx->dataFH = cfopen_write(fname, PG_BINARY_W, AH->compression);
290         if (ctx->dataFH == NULL)
291                 exit_horribly(modulename, "could not open output file \"%s\": %s\n",
292                                           fname, strerror(errno));
293 }
294
295 /*
296  * Called by archiver when dumper calls WriteData. This routine is
297  * called for both BLOB and TABLE data; it is the responsibility of
298  * the format to manage each kind of data using StartBlob/StartData.
299  *
300  * It should only be called from within a DataDumper routine.
301  *
302  * We write the data to the open data file.
303  */
304 static size_t
305 _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
306 {
307         lclContext *ctx = (lclContext *) AH->formatData;
308
309         if (dLen == 0)
310                 return 0;
311
312         return cfwrite(data, dLen, ctx->dataFH);
313 }
314
315 /*
316  * Called by the archiver when a dumper's 'DataDumper' routine has
317  * finished.
318  *
319  * We close the data file.
320  */
321 static void
322 _EndData(ArchiveHandle *AH, TocEntry *te)
323 {
324         lclContext *ctx = (lclContext *) AH->formatData;
325
326         /* Close the file */
327         cfclose(ctx->dataFH);
328
329         ctx->dataFH = NULL;
330 }
331
332 /*
333  * Print data for a given file (can be a BLOB as well)
334  */
335 static void
336 _PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
337 {
338         size_t          cnt;
339         char       *buf;
340         size_t          buflen;
341         cfp                *cfp;
342
343         if (!filename)
344                 return;
345
346         cfp = cfopen_read(filename, PG_BINARY_R);
347
348         if (!cfp)
349                 exit_horribly(modulename, "could not open input file \"%s\": %s\n",
350                                           filename, strerror(errno));
351
352         buf = pg_malloc(ZLIB_OUT_SIZE);
353         buflen = ZLIB_OUT_SIZE;
354
355         while ((cnt = cfread(buf, buflen, cfp)))
356                 ahwrite(buf, 1, cnt, AH);
357
358         free(buf);
359         if (cfclose(cfp) !=0)
360                 exit_horribly(modulename, "could not close data file: %s\n",
361                                           strerror(errno));
362 }
363
364 /*
365  * Print data for a given TOC entry
366 */
367 static void
368 _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
369 {
370         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
371
372         if (!tctx->filename)
373                 return;
374
375         if (strcmp(te->desc, "BLOBS") == 0)
376                 _LoadBlobs(AH, ropt);
377         else
378         {
379                 char       *fname = prependDirectory(AH, tctx->filename);
380
381                 _PrintFileData(AH, fname, ropt);
382         }
383 }
384
385 static void
386 _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
387 {
388         Oid                     oid;
389         lclContext *ctx = (lclContext *) AH->formatData;
390         char       *fname;
391         char            line[MAXPGPATH];
392
393         StartRestoreBlobs(AH);
394
395         fname = prependDirectory(AH, "blobs.toc");
396
397         ctx->blobsTocFH = cfopen_read(fname, PG_BINARY_R);
398
399         if (ctx->blobsTocFH == NULL)
400                 exit_horribly(modulename, "could not open large object TOC file \"%s\" for input: %s\n",
401                                           fname, strerror(errno));
402
403         /* Read the blobs TOC file line-by-line, and process each blob */
404         while ((cfgets(ctx->blobsTocFH, line, MAXPGPATH)) != NULL)
405         {
406                 char            fname[MAXPGPATH];
407                 char            path[MAXPGPATH];
408
409                 if (sscanf(line, "%u %s\n", &oid, fname) != 2)
410                         exit_horribly(modulename, "invalid line in large object TOC file \"%s\": \"%s\"\n",
411                                                   fname, line);
412
413                 StartRestoreBlob(AH, oid, ropt->dropSchema);
414                 snprintf(path, MAXPGPATH, "%s/%s", ctx->directory, fname);
415                 _PrintFileData(AH, path, ropt);
416                 EndRestoreBlob(AH, oid);
417         }
418         if (!cfeof(ctx->blobsTocFH))
419                 exit_horribly(modulename, "error reading large object TOC file \"%s\"\n",
420                                           fname);
421
422         if (cfclose(ctx->blobsTocFH) != 0)
423                 exit_horribly(modulename, "could not close large object TOC file \"%s\": %s\n",
424                                           fname, strerror(errno));
425
426         ctx->blobsTocFH = NULL;
427
428         EndRestoreBlobs(AH);
429 }
430
431
432 /*
433  * Write a byte of data to the archive.
434  * Called by the archiver to do integer & byte output to the archive.
435  * These routines are only used to read & write the headers & TOC.
436  */
437 static int
438 _WriteByte(ArchiveHandle *AH, const int i)
439 {
440         unsigned char c = (unsigned char) i;
441         lclContext *ctx = (lclContext *) AH->formatData;
442
443         if (cfwrite(&c, 1, ctx->dataFH) != 1)
444                 exit_horribly(modulename, "could not write byte\n");
445
446         return 1;
447 }
448
449 /*
450  * Read a byte of data from the archive.
451  * Called by the archiver to read bytes & integers from the archive.
452  * These routines are only used to read & write headers & TOC.
453  * EOF should be treated as a fatal error.
454  */
455 static int
456 _ReadByte(ArchiveHandle *AH)
457 {
458         lclContext *ctx = (lclContext *) AH->formatData;
459         int                     res;
460
461         res = cfgetc(ctx->dataFH);
462         if (res == EOF)
463                 exit_horribly(modulename, "unexpected end of file\n");
464
465         return res;
466 }
467
468 /*
469  * Write a buffer of data to the archive.
470  * Called by the archiver to write a block of bytes to the TOC or a data file.
471  */
472 static size_t
473 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
474 {
475         lclContext *ctx = (lclContext *) AH->formatData;
476         size_t          res;
477
478         res = cfwrite(buf, len, ctx->dataFH);
479         if (res != len)
480                 exit_horribly(modulename, "could not write to output file: %s\n",
481                                           strerror(errno));
482
483         return res;
484 }
485
486 /*
487  * Read a block of bytes from the archive.
488  *
489  * Called by the archiver to read a block of bytes from the archive
490  */
491 static size_t
492 _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
493 {
494         lclContext *ctx = (lclContext *) AH->formatData;
495         size_t          res;
496
497         res = cfread(buf, len, ctx->dataFH);
498
499         return res;
500 }
501
502 /*
503  * Close the archive.
504  *
505  * When writing the archive, this is the routine that actually starts
506  * the process of saving it to files. No data should be written prior
507  * to this point, since the user could sort the TOC after creating it.
508  *
509  * If an archive is to be written, this routine must call:
510  *              WriteHead                       to save the archive header
511  *              WriteToc                        to save the TOC entries
512  *              WriteDataChunks         to save all DATA & BLOBs.
513  */
514 static void
515 _CloseArchive(ArchiveHandle *AH)
516 {
517         lclContext *ctx = (lclContext *) AH->formatData;
518
519         if (AH->mode == archModeWrite)
520         {
521                 cfp                *tocFH;
522                 char       *fname = prependDirectory(AH, "toc.dat");
523
524                 /* The TOC is always created uncompressed */
525                 tocFH = cfopen_write(fname, PG_BINARY_W, 0);
526                 if (tocFH == NULL)
527                         exit_horribly(modulename, "could not open output file \"%s\": %s\n",
528                                                   fname, strerror(errno));
529                 ctx->dataFH = tocFH;
530
531                 /*
532                  * Write 'tar' in the format field of the toc.dat file. The directory
533                  * is compatible with 'tar', so there's no point having a different
534                  * format code for it.
535                  */
536                 AH->format = archTar;
537                 WriteHead(AH);
538                 AH->format = archDirectory;
539                 WriteToc(AH);
540                 if (cfclose(tocFH) != 0)
541                         exit_horribly(modulename, "could not close TOC file: %s\n",
542                                                   strerror(errno));
543                 WriteDataChunks(AH);
544         }
545         AH->FH = NULL;
546 }
547
548
549 /*
550  * BLOB support
551  */
552
553 /*
554  * Called by the archiver when starting to save all BLOB DATA (not schema).
555  * It is called just prior to the dumper's DataDumper routine.
556  *
557  * We open the large object TOC file here, so that we can append a line to
558  * it for each blob.
559  */
560 static void
561 _StartBlobs(ArchiveHandle *AH, TocEntry *te)
562 {
563         lclContext *ctx = (lclContext *) AH->formatData;
564         char       *fname;
565
566         fname = prependDirectory(AH, "blobs.toc");
567
568         /* The blob TOC file is never compressed */
569         ctx->blobsTocFH = cfopen_write(fname, "ab", 0);
570         if (ctx->blobsTocFH == NULL)
571                 exit_horribly(modulename, "could not open output file \"%s\": %s\n",
572                                           fname, strerror(errno));
573 }
574
575 /*
576  * Called by the archiver when we're about to start dumping a blob.
577  *
578  * We create a file to write the blob to.
579  */
580 static void
581 _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
582 {
583         lclContext *ctx = (lclContext *) AH->formatData;
584         char            fname[MAXPGPATH];
585
586         snprintf(fname, MAXPGPATH, "%s/blob_%u.dat", ctx->directory, oid);
587
588         ctx->dataFH = cfopen_write(fname, PG_BINARY_W, AH->compression);
589
590         if (ctx->dataFH == NULL)
591                 exit_horribly(modulename, "could not open output file \"%s\": %s\n",
592                                           fname, strerror(errno));
593 }
594
595 /*
596  * Called by the archiver when the dumper is finished writing a blob.
597  *
598  * We close the blob file and write an entry to the blob TOC file for it.
599  */
600 static void
601 _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
602 {
603         lclContext *ctx = (lclContext *) AH->formatData;
604         char            buf[50];
605         int                     len;
606
607         /* Close the BLOB data file itself */
608         cfclose(ctx->dataFH);
609         ctx->dataFH = NULL;
610
611         /* register the blob in blobs.toc */
612         len = snprintf(buf, sizeof(buf), "%u blob_%u.dat\n", oid, oid);
613         if (cfwrite(buf, len, ctx->blobsTocFH) != len)
614                 exit_horribly(modulename, "could not write to blobs TOC file\n");
615 }
616
617 /*
618  * Called by the archiver when finishing saving all BLOB DATA.
619  *
620  * We close the blobs TOC file.
621  */
622 static void
623 _EndBlobs(ArchiveHandle *AH, TocEntry *te)
624 {
625         lclContext *ctx = (lclContext *) AH->formatData;
626
627         cfclose(ctx->blobsTocFH);
628         ctx->blobsTocFH = NULL;
629 }
630
631 static void
632 createDirectory(const char *dir)
633 {
634         struct stat st;
635
636         /* the directory must not exist yet. */
637         if (stat(dir, &st) == 0)
638         {
639                 if (S_ISDIR(st.st_mode))
640                         exit_horribly(modulename,
641                                                   "cannot create directory %s, it exists already\n",
642                                                   dir);
643                 else
644                         exit_horribly(modulename,
645                                                   "cannot create directory %s, a file with this name "
646                                                   "exists already\n", dir);
647         }
648
649         /*
650          * Now we create the directory. Note that for some race condition we could
651          * also run into the situation that the directory has been created just
652          * between our two calls.
653          */
654         if (mkdir(dir, 0700) < 0)
655                 exit_horribly(modulename, "could not create directory %s: %s\n",
656                                           dir, strerror(errno));
657 }
658
659
660 static char *
661 prependDirectory(ArchiveHandle *AH, const char *relativeFilename)
662 {
663         lclContext *ctx = (lclContext *) AH->formatData;
664         static char buf[MAXPGPATH];
665         char       *dname;
666
667         dname = ctx->directory;
668
669         if (strlen(dname) + 1 + strlen(relativeFilename) + 1 > MAXPGPATH)
670                 exit_horribly(modulename, "file name too long: \"%s\"\n", dname);
671
672         strcpy(buf, dname);
673         strcat(buf, "/");
674         strcat(buf, relativeFilename);
675
676         return buf;
677 }