LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_backup_directory.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 88.8 % 267 237
Test Date: 2026-07-11 05:15:30 Functions: 100.0 % 27 27
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 60.6 % 94 57

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

Generated by: LCOV version 2.0-1