LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_backup_tar.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 368 452 81.4 %
Date: 2020-05-25 06:06:29 Functions: 32 32 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_backup_tar.c
       4             :  *
       5             :  *  This file is copied from the 'files' format file, but dumps data into
       6             :  *  one temp file then sends it to the output TAR archive.
       7             :  *
       8             :  *  The tar format also includes a 'restore.sql' script which is there for
       9             :  *  the benefit of humans. This script is never used by pg_restore.
      10             :  *
      11             :  *  NOTE: If you untar the created 'tar' file, the resulting files are
      12             :  *  compatible with the 'directory' format. Please keep the two formats in
      13             :  *  sync.
      14             :  *
      15             :  *  See the headers to pg_backup_directory & pg_restore for more details.
      16             :  *
      17             :  * Copyright (c) 2000, Philip Warner
      18             :  *      Rights are granted to use this software in any way so long
      19             :  *      as this notice is not removed.
      20             :  *
      21             :  *  The author is not responsible for loss or damages that may
      22             :  *  result from its use.
      23             :  *
      24             :  *
      25             :  * IDENTIFICATION
      26             :  *      src/bin/pg_dump/pg_backup_tar.c
      27             :  *
      28             :  *-------------------------------------------------------------------------
      29             :  */
      30             : #include "postgres_fe.h"
      31             : 
      32             : #include <sys/stat.h>
      33             : #include <ctype.h>
      34             : #include <limits.h>
      35             : #include <unistd.h>
      36             : 
      37             : #include "common/file_utils.h"
      38             : #include "fe_utils/string_utils.h"
      39             : #include "pg_backup_archiver.h"
      40             : #include "pg_backup_tar.h"
      41             : #include "pg_backup_utils.h"
      42             : #include "pgtar.h"
      43             : 
      44             : static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
      45             : static void _StartData(ArchiveHandle *AH, TocEntry *te);
      46             : static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
      47             : static void _EndData(ArchiveHandle *AH, TocEntry *te);
      48             : static int  _WriteByte(ArchiveHandle *AH, const int i);
      49             : static int  _ReadByte(ArchiveHandle *);
      50             : static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
      51             : static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len);
      52             : static void _CloseArchive(ArchiveHandle *AH);
      53             : static void _PrintTocData(ArchiveHandle *AH, TocEntry *te);
      54             : static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
      55             : static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
      56             : static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
      57             : 
      58             : static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
      59             : static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
      60             : static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
      61             : static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
      62             : 
      63             : #define K_STD_BUF_SIZE 1024
      64             : 
      65             : 
      66             : typedef struct
      67             : {
      68             : #ifdef HAVE_LIBZ
      69             :     gzFile      zFH;
      70             : #else
      71             :     FILE       *zFH;
      72             : #endif
      73             :     FILE       *nFH;
      74             :     FILE       *tarFH;
      75             :     FILE       *tmpFH;
      76             :     char       *targetFile;
      77             :     char        mode;
      78             :     pgoff_t     pos;
      79             :     pgoff_t     fileLen;
      80             :     ArchiveHandle *AH;
      81             : } TAR_MEMBER;
      82             : 
      83             : typedef struct
      84             : {
      85             :     int         hasSeek;
      86             :     pgoff_t     filePos;
      87             :     TAR_MEMBER *blobToc;
      88             :     FILE       *tarFH;
      89             :     pgoff_t     tarFHpos;
      90             :     pgoff_t     tarNextMember;
      91             :     TAR_MEMBER *FH;
      92             :     int         isSpecialScript;
      93             :     TAR_MEMBER *scriptTH;
      94             : } lclContext;
      95             : 
      96             : typedef struct
      97             : {
      98             :     TAR_MEMBER *TH;
      99             :     char       *filename;
     100             : } lclTocEntry;
     101             : 
     102             : static void _LoadBlobs(ArchiveHandle *AH);
     103             : 
     104             : static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);
     105             : static void tarClose(ArchiveHandle *AH, TAR_MEMBER *TH);
     106             : 
     107             : #ifdef __NOT_USED__
     108             : static char *tarGets(char *buf, size_t len, TAR_MEMBER *th);
     109             : #endif
     110             : static int  tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...) pg_attribute_printf(3, 4);
     111             : 
     112             : static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th);
     113             : static TAR_MEMBER *_tarPositionTo(ArchiveHandle *AH, const char *filename);
     114             : static size_t tarRead(void *buf, size_t len, TAR_MEMBER *th);
     115             : static size_t tarWrite(const void *buf, size_t len, TAR_MEMBER *th);
     116             : static void _tarWriteHeader(TAR_MEMBER *th);
     117             : static int  _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th);
     118             : static size_t _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh);
     119             : 
     120             : static size_t _scriptOut(ArchiveHandle *AH, const void *buf, size_t len);
     121             : 
     122             : /*
     123             :  *  Initializer
     124             :  */
     125             : void
     126           8 : InitArchiveFmt_Tar(ArchiveHandle *AH)
     127             : {
     128             :     lclContext *ctx;
     129             : 
     130             :     /* Assuming static functions, this can be copied for each format. */
     131           8 :     AH->ArchiveEntryPtr = _ArchiveEntry;
     132           8 :     AH->StartDataPtr = _StartData;
     133           8 :     AH->WriteDataPtr = _WriteData;
     134           8 :     AH->EndDataPtr = _EndData;
     135           8 :     AH->WriteBytePtr = _WriteByte;
     136           8 :     AH->ReadBytePtr = _ReadByte;
     137           8 :     AH->WriteBufPtr = _WriteBuf;
     138           8 :     AH->ReadBufPtr = _ReadBuf;
     139           8 :     AH->ClosePtr = _CloseArchive;
     140           8 :     AH->ReopenPtr = NULL;
     141           8 :     AH->PrintTocDataPtr = _PrintTocData;
     142           8 :     AH->ReadExtraTocPtr = _ReadExtraToc;
     143           8 :     AH->WriteExtraTocPtr = _WriteExtraToc;
     144           8 :     AH->PrintExtraTocPtr = _PrintExtraToc;
     145             : 
     146           8 :     AH->StartBlobsPtr = _StartBlobs;
     147           8 :     AH->StartBlobPtr = _StartBlob;
     148           8 :     AH->EndBlobPtr = _EndBlob;
     149           8 :     AH->EndBlobsPtr = _EndBlobs;
     150           8 :     AH->ClonePtr = NULL;
     151           8 :     AH->DeClonePtr = NULL;
     152             : 
     153           8 :     AH->WorkerJobDumpPtr = NULL;
     154           8 :     AH->WorkerJobRestorePtr = NULL;
     155             : 
     156             :     /*
     157             :      * Set up some special context used in compressing data.
     158             :      */
     159           8 :     ctx = (lclContext *) pg_malloc0(sizeof(lclContext));
     160           8 :     AH->formatData = (void *) ctx;
     161           8 :     ctx->filePos = 0;
     162           8 :     ctx->isSpecialScript = 0;
     163             : 
     164             :     /* Initialize LO buffering */
     165           8 :     AH->lo_buf_size = LOBBUFSIZE;
     166           8 :     AH->lo_buf = (void *) pg_malloc(LOBBUFSIZE);
     167             : 
     168             :     /*
     169             :      * Now open the tar file, and load the TOC if we're in read mode.
     170             :      */
     171           8 :     if (AH->mode == archModeWrite)
     172             :     {
     173           4 :         if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
     174             :         {
     175           4 :             ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);
     176           4 :             if (ctx->tarFH == NULL)
     177           0 :                 fatal("could not open TOC file \"%s\" for output: %m",
     178             :                       AH->fSpec);
     179             :         }
     180             :         else
     181             :         {
     182           0 :             ctx->tarFH = stdout;
     183           0 :             if (ctx->tarFH == NULL)
     184           0 :                 fatal("could not open TOC file for output: %m");
     185             :         }
     186             : 
     187           4 :         ctx->tarFHpos = 0;
     188             : 
     189             :         /*
     190             :          * Make unbuffered since we will dup() it, and the buffers screw each
     191             :          * other
     192             :          */
     193             :         /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
     194             : 
     195           4 :         ctx->hasSeek = checkSeek(ctx->tarFH);
     196             : 
     197             :         /*
     198             :          * We don't support compression because reading the files back is not
     199             :          * possible since gzdopen uses buffered IO which totally screws file
     200             :          * positioning.
     201             :          */
     202           4 :         if (AH->compression != 0)
     203           0 :             fatal("compression is not supported by tar archive format");
     204             :     }
     205             :     else
     206             :     {                           /* Read Mode */
     207           4 :         if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
     208             :         {
     209           4 :             ctx->tarFH = fopen(AH->fSpec, PG_BINARY_R);
     210           4 :             if (ctx->tarFH == NULL)
     211           0 :                 fatal("could not open TOC file \"%s\" for input: %m",
     212             :                       AH->fSpec);
     213             :         }
     214             :         else
     215             :         {
     216           0 :             ctx->tarFH = stdin;
     217           0 :             if (ctx->tarFH == NULL)
     218           0 :                 fatal("could not open TOC file for input: %m");
     219             :         }
     220             : 
     221             :         /*
     222             :          * Make unbuffered since we will dup() it, and the buffers screw each
     223             :          * other
     224             :          */
     225             :         /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
     226             : 
     227           4 :         ctx->tarFHpos = 0;
     228             : 
     229           4 :         ctx->hasSeek = checkSeek(ctx->tarFH);
     230             : 
     231             :         /*
     232             :          * Forcibly unmark the header as read since we use the lookahead
     233             :          * buffer
     234             :          */
     235           4 :         AH->readHeader = 0;
     236             : 
     237           4 :         ctx->FH = (void *) tarOpen(AH, "toc.dat", 'r');
     238           4 :         ReadHead(AH);
     239           4 :         ReadToc(AH);
     240           4 :         tarClose(AH, ctx->FH);   /* Nothing else in the file... */
     241             :     }
     242           8 : }
     243             : 
     244             : /*
     245             :  * - Start a new TOC entry
     246             :  *   Setup the output file name.
     247             :  */
     248             : static void
     249         434 : _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
     250             : {
     251             :     lclTocEntry *ctx;
     252             :     char        fn[K_STD_BUF_SIZE];
     253             : 
     254         434 :     ctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
     255         434 :     if (te->dataDumper != NULL)
     256             :     {
     257             : #ifdef HAVE_LIBZ
     258          36 :         if (AH->compression == 0)
     259          36 :             sprintf(fn, "%d.dat", te->dumpId);
     260             :         else
     261           0 :             sprintf(fn, "%d.dat.gz", te->dumpId);
     262             : #else
     263             :         sprintf(fn, "%d.dat", te->dumpId);
     264             : #endif
     265          36 :         ctx->filename = pg_strdup(fn);
     266             :     }
     267             :     else
     268             :     {
     269         398 :         ctx->filename = NULL;
     270         398 :         ctx->TH = NULL;
     271             :     }
     272         434 :     te->formatData = (void *) ctx;
     273         434 : }
     274             : 
     275             : static void
     276         434 : _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
     277             : {
     278         434 :     lclTocEntry *ctx = (lclTocEntry *) te->formatData;
     279             : 
     280         434 :     if (ctx->filename)
     281          36 :         WriteStr(AH, ctx->filename);
     282             :     else
     283         398 :         WriteStr(AH, "");
     284         434 : }
     285             : 
     286             : static void
     287         434 : _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
     288             : {
     289         434 :     lclTocEntry *ctx = (lclTocEntry *) te->formatData;
     290             : 
     291         434 :     if (ctx == NULL)
     292             :     {
     293         434 :         ctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
     294         434 :         te->formatData = (void *) ctx;
     295             :     }
     296             : 
     297         434 :     ctx->filename = ReadStr(AH);
     298         434 :     if (strlen(ctx->filename) == 0)
     299             :     {
     300         398 :         free(ctx->filename);
     301         398 :         ctx->filename = NULL;
     302             :     }
     303         434 :     ctx->TH = NULL;
     304         434 : }
     305             : 
     306             : static void
     307         836 : _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
     308             : {
     309         836 :     lclTocEntry *ctx = (lclTocEntry *) te->formatData;
     310             : 
     311         836 :     if (AH->public.verbose && ctx->filename != NULL)
     312           0 :         ahprintf(AH, "-- File: %s\n", ctx->filename);
     313         836 : }
     314             : 
     315             : static void
     316          34 : _StartData(ArchiveHandle *AH, TocEntry *te)
     317             : {
     318          34 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     319             : 
     320          34 :     tctx->TH = tarOpen(AH, tctx->filename, 'w');
     321          34 : }
     322             : 
     323             : static TAR_MEMBER *
     324          88 : tarOpen(ArchiveHandle *AH, const char *filename, char mode)
     325             : {
     326          88 :     lclContext *ctx = (lclContext *) AH->formatData;
     327             :     TAR_MEMBER *tm;
     328             : 
     329             : #ifdef HAVE_LIBZ
     330             :     char        fmode[14];
     331             : #endif
     332             : 
     333          88 :     if (mode == 'r')
     334             :     {
     335          42 :         tm = _tarPositionTo(AH, filename);
     336          42 :         if (!tm)                /* Not found */
     337             :         {
     338           0 :             if (filename)
     339             :             {
     340             :                 /*
     341             :                  * Couldn't find the requested file. Future: do SEEK(0) and
     342             :                  * retry.
     343             :                  */
     344           0 :                 fatal("could not find file \"%s\" in archive", filename);
     345             :             }
     346             :             else
     347             :             {
     348             :                 /* Any file OK, none left, so return NULL */
     349           0 :                 return NULL;
     350             :             }
     351             :         }
     352             : 
     353             : #ifdef HAVE_LIBZ
     354             : 
     355          42 :         if (AH->compression == 0)
     356          42 :             tm->nFH = ctx->tarFH;
     357             :         else
     358           0 :             fatal("compression is not supported by tar archive format");
     359             :         /* tm->zFH = gzdopen(dup(fileno(ctx->tarFH)), "rb"); */
     360             : #else
     361             :         tm->nFH = ctx->tarFH;
     362             : #endif
     363             :     }
     364             :     else
     365             :     {
     366             :         int         old_umask;
     367             : 
     368          46 :         tm = pg_malloc0(sizeof(TAR_MEMBER));
     369             : 
     370             :         /*
     371             :          * POSIX does not require, but permits, tmpfile() to restrict file
     372             :          * permissions.  Given an OS crash after we write data, the filesystem
     373             :          * might retain the data but forget tmpfile()'s unlink().  If so, the
     374             :          * file mode protects confidentiality of the data written.
     375             :          */
     376          46 :         old_umask = umask(S_IRWXG | S_IRWXO);
     377             : 
     378             : #ifndef WIN32
     379          46 :         tm->tmpFH = tmpfile();
     380             : #else
     381             : 
     382             :         /*
     383             :          * On WIN32, tmpfile() generates a filename in the root directory,
     384             :          * which requires administrative permissions on certain systems. Loop
     385             :          * until we find a unique file name we can create.
     386             :          */
     387             :         while (1)
     388             :         {
     389             :             char       *name;
     390             :             int         fd;
     391             : 
     392             :             name = _tempnam(NULL, "pg_temp_");
     393             :             if (name == NULL)
     394             :                 break;
     395             :             fd = open(name, O_RDWR | O_CREAT | O_EXCL | O_BINARY |
     396             :                       O_TEMPORARY, S_IRUSR | S_IWUSR);
     397             :             free(name);
     398             : 
     399             :             if (fd != -1)       /* created a file */
     400             :             {
     401             :                 tm->tmpFH = fdopen(fd, "w+b");
     402             :                 break;
     403             :             }
     404             :             else if (errno != EEXIST)   /* failure other than file exists */
     405             :                 break;
     406             :         }
     407             : #endif
     408             : 
     409          46 :         if (tm->tmpFH == NULL)
     410           0 :             fatal("could not generate temporary file name: %m");
     411             : 
     412          46 :         umask(old_umask);
     413             : 
     414             : #ifdef HAVE_LIBZ
     415             : 
     416          46 :         if (AH->compression != 0)
     417             :         {
     418           0 :             sprintf(fmode, "wb%d", AH->compression);
     419           0 :             tm->zFH = gzdopen(dup(fileno(tm->tmpFH)), fmode);
     420           0 :             if (tm->zFH == NULL)
     421           0 :                 fatal("could not open temporary file");
     422             :         }
     423             :         else
     424          46 :             tm->nFH = tm->tmpFH;
     425             : #else
     426             : 
     427             :         tm->nFH = tm->tmpFH;
     428             : #endif
     429             : 
     430          46 :         tm->AH = AH;
     431          46 :         tm->targetFile = pg_strdup(filename);
     432             :     }
     433             : 
     434          88 :     tm->mode = mode;
     435          88 :     tm->tarFH = ctx->tarFH;
     436             : 
     437          88 :     return tm;
     438             : }
     439             : 
     440             : static void
     441          88 : tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
     442             : {
     443             :     /*
     444             :      * Close the GZ file since we dup'd. This will flush the buffers.
     445             :      */
     446          88 :     if (AH->compression != 0)
     447           0 :         if (GZCLOSE(th->zFH) != 0)
     448           0 :             fatal("could not close tar member");
     449             : 
     450          88 :     if (th->mode == 'w')
     451          46 :         _tarAddFile(AH, th);    /* This will close the temp file */
     452             : 
     453             :     /*
     454             :      * else Nothing to do for normal read since we don't dup() normal file
     455             :      * handle, and we don't use temp files.
     456             :      */
     457             : 
     458          88 :     if (th->targetFile)
     459          88 :         free(th->targetFile);
     460             : 
     461          88 :     th->nFH = NULL;
     462          88 :     th->zFH = NULL;
     463          88 : }
     464             : 
     465             : #ifdef __NOT_USED__
     466             : static char *
     467             : tarGets(char *buf, size_t len, TAR_MEMBER *th)
     468             : {
     469             :     char       *s;
     470             :     size_t      cnt = 0;
     471             :     char        c = ' ';
     472             :     int         eof = 0;
     473             : 
     474             :     /* Can't read past logical EOF */
     475             :     if (len > (th->fileLen - th->pos))
     476             :         len = th->fileLen - th->pos;
     477             : 
     478             :     while (cnt < len && c != '\n')
     479             :     {
     480             :         if (_tarReadRaw(th->AH, &c, 1, th, NULL) <= 0)
     481             :         {
     482             :             eof = 1;
     483             :             break;
     484             :         }
     485             :         buf[cnt++] = c;
     486             :     }
     487             : 
     488             :     if (eof && cnt == 0)
     489             :         s = NULL;
     490             :     else
     491             :     {
     492             :         buf[cnt++] = '\0';
     493             :         s = buf;
     494             :     }
     495             : 
     496             :     if (s)
     497             :     {
     498             :         len = strlen(s);
     499             :         th->pos += len;
     500             :     }
     501             : 
     502             :     return s;
     503             : }
     504             : #endif
     505             : 
     506             : /*
     507             :  * Just read bytes from the archive. This is the low level read routine
     508             :  * that is used for ALL reads on a tar file.
     509             :  */
     510             : static size_t
     511       61562 : _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
     512             : {
     513       61562 :     lclContext *ctx = (lclContext *) AH->formatData;
     514             :     size_t      avail;
     515       61562 :     size_t      used = 0;
     516       61562 :     size_t      res = 0;
     517             : 
     518             :     Assert(th || fh);
     519             : 
     520       61562 :     avail = AH->lookaheadLen - AH->lookaheadPos;
     521       61562 :     if (avail > 0)
     522             :     {
     523             :         /* We have some lookahead bytes to use */
     524           0 :         if (avail >= len)        /* Just use the lookahead buffer */
     525           0 :             used = len;
     526             :         else
     527           0 :             used = avail;
     528             : 
     529             :         /* Copy, and adjust buffer pos */
     530           0 :         memcpy(buf, AH->lookahead + AH->lookaheadPos, used);
     531           0 :         AH->lookaheadPos += used;
     532             : 
     533             :         /* Adjust required length */
     534           0 :         len -= used;
     535             :     }
     536             : 
     537             :     /* Read the file if len > 0 */
     538       61562 :     if (len > 0)
     539             :     {
     540       61562 :         if (fh)
     541             :         {
     542       17588 :             res = fread(&((char *) buf)[used], 1, len, fh);
     543       17588 :             if (res != len && !feof(fh))
     544           0 :                 READ_ERROR_EXIT(fh);
     545             :         }
     546       43974 :         else if (th)
     547             :         {
     548       43974 :             if (th->zFH)
     549             :             {
     550           0 :                 res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);
     551           0 :                 if (res != len && !GZEOF(th->zFH))
     552             :                 {
     553             : #ifdef HAVE_LIBZ
     554             :                     int         errnum;
     555           0 :                     const char *errmsg = gzerror(th->zFH, &errnum);
     556             : 
     557           0 :                     fatal("could not read from input file: %s",
     558             :                           errnum == Z_ERRNO ? strerror(errno) : errmsg);
     559             : #else
     560             :                     fatal("could not read from input file: %s",
     561             :                           strerror(errno));
     562             : #endif
     563             :                 }
     564             :             }
     565             :             else
     566             :             {
     567       43974 :                 res = fread(&((char *) buf)[used], 1, len, th->nFH);
     568       43974 :                 if (res != len && !feof(th->nFH))
     569           0 :                     READ_ERROR_EXIT(th->nFH);
     570             :             }
     571             :         }
     572             :     }
     573             : 
     574       61562 :     ctx->tarFHpos += res + used;
     575             : 
     576       61562 :     return (res + used);
     577             : }
     578             : 
     579             : static size_t
     580       44492 : tarRead(void *buf, size_t len, TAR_MEMBER *th)
     581             : {
     582             :     size_t      res;
     583             : 
     584       44492 :     if (th->pos + len > th->fileLen)
     585          72 :         len = th->fileLen - th->pos;
     586             : 
     587       44492 :     if (len <= 0)
     588         518 :         return 0;
     589             : 
     590       43974 :     res = _tarReadRaw(th->AH, buf, len, th, NULL);
     591             : 
     592       43974 :     th->pos += res;
     593             : 
     594       43974 :     return res;
     595             : }
     596             : 
     597             : static size_t
     598       47000 : tarWrite(const void *buf, size_t len, TAR_MEMBER *th)
     599             : {
     600             :     size_t      res;
     601             : 
     602       47000 :     if (th->zFH != NULL)
     603           0 :         res = GZWRITE(buf, 1, len, th->zFH);
     604             :     else
     605       47000 :         res = fwrite(buf, 1, len, th->nFH);
     606             : 
     607       47000 :     th->pos += res;
     608       47000 :     return res;
     609             : }
     610             : 
     611             : static void
     612          92 : _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
     613             : {
     614          92 :     lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
     615             : 
     616          92 :     if (tarWrite(data, dLen, tctx->TH) != dLen)
     617           0 :         WRITE_ERROR_EXIT;
     618          92 : }
     619             : 
     620             : static void
     621          34 : _EndData(ArchiveHandle *AH, TocEntry *te)
     622             : {
     623          34 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     624             : 
     625             :     /* Close the file */
     626          34 :     tarClose(AH, tctx->TH);
     627          34 :     tctx->TH = NULL;
     628          34 : }
     629             : 
     630             : /*
     631             :  * Print data for a given file
     632             :  */
     633             : static void
     634          34 : _PrintFileData(ArchiveHandle *AH, char *filename)
     635             : {
     636          34 :     lclContext *ctx = (lclContext *) AH->formatData;
     637             :     char        buf[4096];
     638             :     size_t      cnt;
     639             :     TAR_MEMBER *th;
     640             : 
     641          34 :     if (!filename)
     642           0 :         return;
     643             : 
     644          34 :     th = tarOpen(AH, filename, 'r');
     645          34 :     ctx->FH = th;
     646             : 
     647          68 :     while ((cnt = tarRead(buf, 4095, th)) > 0)
     648             :     {
     649          34 :         buf[cnt] = '\0';
     650          34 :         ahwrite(buf, 1, cnt, AH);
     651             :     }
     652             : 
     653          34 :     tarClose(AH, th);
     654             : }
     655             : 
     656             : 
     657             : /*
     658             :  * Print data for a given TOC entry
     659             : */
     660             : static void
     661          72 : _PrintTocData(ArchiveHandle *AH, TocEntry *te)
     662             : {
     663          72 :     lclContext *ctx = (lclContext *) AH->formatData;
     664          72 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     665             :     int         pos1;
     666             : 
     667          72 :     if (!tctx->filename)
     668           0 :         return;
     669             : 
     670             :     /*
     671             :      * If we're writing the special restore.sql script, emit a suitable
     672             :      * command to include each table's data from the corresponding file.
     673             :      *
     674             :      * In the COPY case this is a bit klugy because the regular COPY command
     675             :      * was already printed before we get control.
     676             :      */
     677          72 :     if (ctx->isSpecialScript)
     678             :     {
     679          36 :         if (te->copyStmt)
     680             :         {
     681             :             /* Abort the COPY FROM stdin */
     682          34 :             ahprintf(AH, "\\.\n");
     683             : 
     684             :             /*
     685             :              * The COPY statement should look like "COPY ... FROM stdin;\n",
     686             :              * see dumpTableData().
     687             :              */
     688          34 :             pos1 = (int) strlen(te->copyStmt) - 13;
     689          34 :             if (pos1 < 6 || strncmp(te->copyStmt, "COPY ", 5) != 0 ||
     690          34 :                 strcmp(te->copyStmt + pos1, " FROM stdin;\n") != 0)
     691           0 :                 fatal("unexpected COPY statement syntax: \"%s\"",
     692             :                       te->copyStmt);
     693             : 
     694             :             /* Emit all but the FROM part ... */
     695          34 :             ahwrite(te->copyStmt, 1, pos1, AH);
     696             :             /* ... and insert modified FROM */
     697          34 :             ahprintf(AH, " FROM '$$PATH$$/%s';\n\n", tctx->filename);
     698             :         }
     699             :         else
     700             :         {
     701             :             /* --inserts mode, no worries, just include the data file */
     702           2 :             ahprintf(AH, "\\i $$PATH$$/%s\n\n", tctx->filename);
     703             :         }
     704             : 
     705          36 :         return;
     706             :     }
     707             : 
     708          36 :     if (strcmp(te->desc, "BLOBS") == 0)
     709           2 :         _LoadBlobs(AH);
     710             :     else
     711          34 :         _PrintFileData(AH, tctx->filename);
     712             : }
     713             : 
     714             : static void
     715           2 : _LoadBlobs(ArchiveHandle *AH)
     716             : {
     717             :     Oid         oid;
     718           2 :     lclContext *ctx = (lclContext *) AH->formatData;
     719             :     TAR_MEMBER *th;
     720             :     size_t      cnt;
     721           2 :     bool        foundBlob = false;
     722             :     char        buf[4096];
     723             : 
     724           2 :     StartRestoreBlobs(AH);
     725             : 
     726           2 :     th = tarOpen(AH, NULL, 'r');    /* Open next file */
     727           4 :     while (th != NULL)
     728             :     {
     729           4 :         ctx->FH = th;
     730             : 
     731           4 :         if (strncmp(th->targetFile, "blob_", 5) == 0)
     732             :         {
     733           2 :             oid = atooid(&th->targetFile[5]);
     734           2 :             if (oid != 0)
     735             :             {
     736           2 :                 pg_log_info("restoring large object with OID %u", oid);
     737             : 
     738           2 :                 StartRestoreBlob(AH, oid, AH->public.ropt->dropSchema);
     739             : 
     740           4 :                 while ((cnt = tarRead(buf, 4095, th)) > 0)
     741             :                 {
     742           2 :                     buf[cnt] = '\0';
     743           2 :                     ahwrite(buf, 1, cnt, AH);
     744             :                 }
     745           2 :                 EndRestoreBlob(AH, oid);
     746           2 :                 foundBlob = true;
     747             :             }
     748           2 :             tarClose(AH, th);
     749             :         }
     750             :         else
     751             :         {
     752           2 :             tarClose(AH, th);
     753             : 
     754             :             /*
     755             :              * Once we have found the first blob, stop at the first non-blob
     756             :              * entry (which will be 'blobs.toc').  This coding would eat all
     757             :              * the rest of the archive if there are no blobs ... but this
     758             :              * function shouldn't be called at all in that case.
     759             :              */
     760           2 :             if (foundBlob)
     761           2 :                 break;
     762             :         }
     763             : 
     764           2 :         th = tarOpen(AH, NULL, 'r');
     765             :     }
     766           2 :     EndRestoreBlobs(AH);
     767           2 : }
     768             : 
     769             : 
     770             : static int
     771       39764 : _WriteByte(ArchiveHandle *AH, const int i)
     772             : {
     773       39764 :     lclContext *ctx = (lclContext *) AH->formatData;
     774       39764 :     char        b = i;          /* Avoid endian problems */
     775             : 
     776       39764 :     if (tarWrite(&b, 1, ctx->FH) != 1)
     777           0 :         WRITE_ERROR_EXIT;
     778             : 
     779       39764 :     ctx->filePos += 1;
     780       39764 :     return 1;
     781             : }
     782             : 
     783             : static int
     784       39764 : _ReadByte(ArchiveHandle *AH)
     785             : {
     786       39764 :     lclContext *ctx = (lclContext *) AH->formatData;
     787             :     size_t      res;
     788             :     unsigned char c;
     789             : 
     790       39764 :     res = tarRead(&c, 1, ctx->FH);
     791       39764 :     if (res != 1)
     792             :         /* We already would have exited for errors on reads, must be EOF */
     793           0 :         fatal("could not read from input file: end of file");
     794       39764 :     ctx->filePos += 1;
     795       39764 :     return c;
     796             : }
     797             : 
     798             : static void
     799        4656 : _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
     800             : {
     801        4656 :     lclContext *ctx = (lclContext *) AH->formatData;
     802             : 
     803        4656 :     if (tarWrite(buf, len, ctx->FH) != len)
     804           0 :         WRITE_ERROR_EXIT;
     805             : 
     806        4656 :     ctx->filePos += len;
     807        4656 : }
     808             : 
     809             : static void
     810        4656 : _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
     811             : {
     812        4656 :     lclContext *ctx = (lclContext *) AH->formatData;
     813             : 
     814        4656 :     if (tarRead(buf, len, ctx->FH) != len)
     815             :         /* We already would have exited for errors on reads, must be EOF */
     816           0 :         fatal("could not read from input file: end of file");
     817             : 
     818        4656 :     ctx->filePos += len;
     819        4656 : }
     820             : 
     821             : static void
     822           8 : _CloseArchive(ArchiveHandle *AH)
     823             : {
     824           8 :     lclContext *ctx = (lclContext *) AH->formatData;
     825             :     TAR_MEMBER *th;
     826             :     RestoreOptions *ropt;
     827             :     RestoreOptions *savRopt;
     828             :     DumpOptions *savDopt;
     829             :     int         savVerbose,
     830             :                 i;
     831             : 
     832           8 :     if (AH->mode == archModeWrite)
     833             :     {
     834             :         /*
     835             :          * Write the Header & TOC to the archive FIRST
     836             :          */
     837           4 :         th = tarOpen(AH, "toc.dat", 'w');
     838           4 :         ctx->FH = th;
     839           4 :         WriteHead(AH);
     840           4 :         WriteToc(AH);
     841           4 :         tarClose(AH, th);       /* Not needed any more */
     842             : 
     843             :         /*
     844             :          * Now send the data (tables & blobs)
     845             :          */
     846           4 :         WriteDataChunks(AH, NULL);
     847             : 
     848             :         /*
     849             :          * Now this format wants to append a script which does a full restore
     850             :          * if the files have been extracted.
     851             :          */
     852           4 :         th = tarOpen(AH, "restore.sql", 'w');
     853             : 
     854           4 :         tarPrintf(AH, th, "--\n"
     855             :                   "-- NOTE:\n"
     856             :                   "--\n"
     857             :                   "-- File paths need to be edited. Search for $$PATH$$ and\n"
     858             :                   "-- replace it with the path to the directory containing\n"
     859             :                   "-- the extracted data files.\n"
     860             :                   "--\n");
     861             : 
     862           4 :         AH->CustomOutPtr = _scriptOut;
     863             : 
     864           4 :         ctx->isSpecialScript = 1;
     865           4 :         ctx->scriptTH = th;
     866             : 
     867           4 :         ropt = NewRestoreOptions();
     868           4 :         memcpy(ropt, AH->public.ropt, sizeof(RestoreOptions));
     869           4 :         ropt->filename = NULL;
     870           4 :         ropt->dropSchema = 1;
     871           4 :         ropt->compression = 0;
     872           4 :         ropt->superuser = NULL;
     873           4 :         ropt->suppressDumpWarnings = true;
     874             : 
     875           4 :         savDopt = AH->public.dopt;
     876           4 :         savRopt = AH->public.ropt;
     877             : 
     878           4 :         SetArchiveOptions((Archive *) AH, NULL, ropt);
     879             : 
     880           4 :         savVerbose = AH->public.verbose;
     881           4 :         AH->public.verbose = 0;
     882             : 
     883           4 :         RestoreArchive((Archive *) AH);
     884             : 
     885           4 :         SetArchiveOptions((Archive *) AH, savDopt, savRopt);
     886             : 
     887           4 :         AH->public.verbose = savVerbose;
     888             : 
     889           4 :         tarClose(AH, th);
     890             : 
     891           4 :         ctx->isSpecialScript = 0;
     892             : 
     893             :         /*
     894             :          * EOF marker for tar files is two blocks of NULLs.
     895             :          */
     896        4100 :         for (i = 0; i < 512 * 2; i++)
     897             :         {
     898        4096 :             if (fputc(0, ctx->tarFH) == EOF)
     899           0 :                 WRITE_ERROR_EXIT;
     900             :         }
     901             : 
     902             :         /* Sync the output file if one is defined */
     903           4 :         if (AH->dosync && AH->fSpec)
     904           2 :             (void) fsync_fname(AH->fSpec, false);
     905             :     }
     906             : 
     907           8 :     AH->FH = NULL;
     908           8 : }
     909             : 
     910             : static size_t
     911        2482 : _scriptOut(ArchiveHandle *AH, const void *buf, size_t len)
     912             : {
     913        2482 :     lclContext *ctx = (lclContext *) AH->formatData;
     914             : 
     915        2482 :     return tarWrite(buf, len, ctx->scriptTH);
     916             : }
     917             : 
     918             : /*
     919             :  * BLOB support
     920             :  */
     921             : 
     922             : /*
     923             :  * Called by the archiver when starting to save all BLOB DATA (not schema).
     924             :  * This routine should save whatever format-specific information is needed
     925             :  * to read the BLOBs back into memory.
     926             :  *
     927             :  * It is called just prior to the dumper's DataDumper routine.
     928             :  *
     929             :  * Optional, but strongly recommended.
     930             :  *
     931             :  */
     932             : static void
     933           2 : _StartBlobs(ArchiveHandle *AH, TocEntry *te)
     934             : {
     935           2 :     lclContext *ctx = (lclContext *) AH->formatData;
     936             :     char        fname[K_STD_BUF_SIZE];
     937             : 
     938           2 :     sprintf(fname, "blobs.toc");
     939           2 :     ctx->blobToc = tarOpen(AH, fname, 'w');
     940           2 : }
     941             : 
     942             : /*
     943             :  * Called by the archiver when the dumper calls StartBlob.
     944             :  *
     945             :  * Mandatory.
     946             :  *
     947             :  * Must save the passed OID for retrieval at restore-time.
     948             :  */
     949             : static void
     950           2 : _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
     951             : {
     952           2 :     lclContext *ctx = (lclContext *) AH->formatData;
     953           2 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     954             :     char        fname[255];
     955             :     char       *sfx;
     956             : 
     957           2 :     if (oid == 0)
     958           0 :         fatal("invalid OID for large object (%u)", oid);
     959             : 
     960           2 :     if (AH->compression != 0)
     961           0 :         sfx = ".gz";
     962             :     else
     963           2 :         sfx = "";
     964             : 
     965           2 :     sprintf(fname, "blob_%u.dat%s", oid, sfx);
     966             : 
     967           2 :     tarPrintf(AH, ctx->blobToc, "%u %s\n", oid, fname);
     968             : 
     969           2 :     tctx->TH = tarOpen(AH, fname, 'w');
     970           2 : }
     971             : 
     972             : /*
     973             :  * Called by the archiver when the dumper calls EndBlob.
     974             :  *
     975             :  * Optional.
     976             :  *
     977             :  */
     978             : static void
     979           2 : _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
     980             : {
     981           2 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     982             : 
     983           2 :     tarClose(AH, tctx->TH);
     984           2 : }
     985             : 
     986             : /*
     987             :  * Called by the archiver when finishing saving all BLOB DATA.
     988             :  *
     989             :  * Optional.
     990             :  *
     991             :  */
     992             : static void
     993           2 : _EndBlobs(ArchiveHandle *AH, TocEntry *te)
     994             : {
     995           2 :     lclContext *ctx = (lclContext *) AH->formatData;
     996             : 
     997             :     /* Write out a fake zero OID to mark end-of-blobs. */
     998             :     /* WriteInt(AH, 0); */
     999             : 
    1000           2 :     tarClose(AH, ctx->blobToc);
    1001           2 : }
    1002             : 
    1003             : 
    1004             : 
    1005             : /*------------
    1006             :  * TAR Support
    1007             :  *------------
    1008             :  */
    1009             : 
    1010             : static int
    1011           6 : tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...)
    1012             : {
    1013           6 :     int         save_errno = errno;
    1014             :     char       *p;
    1015           6 :     size_t      len = 128;      /* initial assumption about buffer size */
    1016             :     size_t      cnt;
    1017             : 
    1018             :     for (;;)
    1019           4 :     {
    1020             :         va_list     args;
    1021             : 
    1022             :         /* Allocate work buffer. */
    1023          10 :         p = (char *) pg_malloc(len);
    1024             : 
    1025             :         /* Try to format the data. */
    1026          10 :         errno = save_errno;
    1027          10 :         va_start(args, fmt);
    1028          10 :         cnt = pvsnprintf(p, len, fmt, args);
    1029          10 :         va_end(args);
    1030             : 
    1031          10 :         if (cnt < len)
    1032           6 :             break;              /* success */
    1033             : 
    1034             :         /* Release buffer and loop around to try again with larger len. */
    1035           4 :         free(p);
    1036           4 :         len = cnt;
    1037             :     }
    1038             : 
    1039           6 :     cnt = tarWrite(p, cnt, th);
    1040           6 :     free(p);
    1041           6 :     return (int) cnt;
    1042             : }
    1043             : 
    1044             : bool
    1045           2 : isValidTarHeader(char *header)
    1046             : {
    1047             :     int         sum;
    1048           2 :     int         chk = tarChecksum(header);
    1049             : 
    1050           2 :     sum = read_tar_number(&header[148], 8);
    1051             : 
    1052           2 :     if (sum != chk)
    1053           0 :         return false;
    1054             : 
    1055             :     /* POSIX tar format */
    1056           2 :     if (memcmp(&header[257], "ustar\0", 6) == 0 &&
    1057           2 :         memcmp(&header[263], "00", 2) == 0)
    1058           2 :         return true;
    1059             :     /* GNU tar format */
    1060           0 :     if (memcmp(&header[257], "ustar  \0", 8) == 0)
    1061           0 :         return true;
    1062             :     /* not-quite-POSIX format written by pre-9.3 pg_dump */
    1063           0 :     if (memcmp(&header[257], "ustar00\0", 8) == 0)
    1064           0 :         return true;
    1065             : 
    1066           0 :     return false;
    1067             : }
    1068             : 
    1069             : /* Given the member, write the TAR header & copy the file */
    1070             : static void
    1071          46 : _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
    1072             : {
    1073          46 :     lclContext *ctx = (lclContext *) AH->formatData;
    1074          46 :     FILE       *tmp = th->tmpFH; /* Grab it for convenience */
    1075             :     char        buf[32768];
    1076             :     size_t      cnt;
    1077          46 :     pgoff_t     len = 0;
    1078             :     size_t      res;
    1079             :     size_t      i,
    1080             :                 pad;
    1081             : 
    1082             :     /*
    1083             :      * Find file len & go back to start.
    1084             :      */
    1085          46 :     fseeko(tmp, 0, SEEK_END);
    1086          46 :     th->fileLen = ftello(tmp);
    1087          46 :     if (th->fileLen < 0)
    1088           0 :         fatal("could not determine seek position in archive file: %m");
    1089          46 :     fseeko(tmp, 0, SEEK_SET);
    1090             : 
    1091          46 :     _tarWriteHeader(th);
    1092             : 
    1093          96 :     while ((cnt = fread(buf, 1, sizeof(buf), tmp)) > 0)
    1094             :     {
    1095          50 :         if ((res = fwrite(buf, 1, cnt, th->tarFH)) != cnt)
    1096           0 :             WRITE_ERROR_EXIT;
    1097          50 :         len += res;
    1098             :     }
    1099          46 :     if (!feof(tmp))
    1100           0 :         READ_ERROR_EXIT(tmp);
    1101             : 
    1102          46 :     if (fclose(tmp) != 0)       /* This *should* delete it... */
    1103           0 :         fatal("could not close temporary file: %m");
    1104             : 
    1105          46 :     if (len != th->fileLen)
    1106             :     {
    1107             :         char        buf1[32],
    1108             :                     buf2[32];
    1109             : 
    1110           0 :         snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) len);
    1111           0 :         snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) th->fileLen);
    1112           0 :         fatal("actual file length (%s) does not match expected (%s)",
    1113             :               buf1, buf2);
    1114             :     }
    1115             : 
    1116          46 :     pad = ((len + 511) & ~511) - len;
    1117       20870 :     for (i = 0; i < pad; i++)
    1118             :     {
    1119       20824 :         if (fputc('\0', th->tarFH) == EOF)
    1120           0 :             WRITE_ERROR_EXIT;
    1121             :     }
    1122             : 
    1123          46 :     ctx->tarFHpos += len + pad;
    1124          46 : }
    1125             : 
    1126             : /* Locate the file in the archive, read header and position to data */
    1127             : static TAR_MEMBER *
    1128          42 : _tarPositionTo(ArchiveHandle *AH, const char *filename)
    1129             : {
    1130          42 :     lclContext *ctx = (lclContext *) AH->formatData;
    1131          42 :     TAR_MEMBER *th = pg_malloc0(sizeof(TAR_MEMBER));
    1132             :     char        c;
    1133             :     char        header[512];
    1134             :     size_t      i,
    1135             :                 len,
    1136             :                 blks;
    1137             :     int         id;
    1138             : 
    1139          42 :     th->AH = AH;
    1140             : 
    1141             :     /* Go to end of current file, if any */
    1142          42 :     if (ctx->tarFHpos != 0)
    1143             :     {
    1144             :         char        buf1[100],
    1145             :                     buf2[100];
    1146             : 
    1147          38 :         snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) ctx->tarFHpos);
    1148          38 :         snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) ctx->tarNextMember);
    1149          38 :         pg_log_debug("moving from position %s to next member at file position %s",
    1150             :                      buf1, buf2);
    1151             : 
    1152       17584 :         while (ctx->tarFHpos < ctx->tarNextMember)
    1153       17546 :             _tarReadRaw(AH, &c, 1, NULL, ctx->tarFH);
    1154             :     }
    1155             : 
    1156             :     {
    1157             :         char        buf[100];
    1158             : 
    1159          42 :         snprintf(buf, sizeof(buf), INT64_FORMAT, (int64) ctx->tarFHpos);
    1160          42 :         pg_log_debug("now at file position %s", buf);
    1161             :     }
    1162             : 
    1163             :     /* We are at the start of the file, or at the next member */
    1164             : 
    1165             :     /* Get the header */
    1166          42 :     if (!_tarGetHeader(AH, th))
    1167             :     {
    1168           0 :         if (filename)
    1169           0 :             fatal("could not find header for file \"%s\" in tar archive", filename);
    1170             :         else
    1171             :         {
    1172             :             /*
    1173             :              * We're just scanning the archive for the next file, so return
    1174             :              * null
    1175             :              */
    1176           0 :             free(th);
    1177           0 :             return NULL;
    1178             :         }
    1179             :     }
    1180             : 
    1181          42 :     while (filename != NULL && strcmp(th->targetFile, filename) != 0)
    1182             :     {
    1183           0 :         pg_log_debug("skipping tar member %s", th->targetFile);
    1184             : 
    1185           0 :         id = atoi(th->targetFile);
    1186           0 :         if ((TocIDRequired(AH, id) & REQ_DATA) != 0)
    1187           0 :             fatal("restoring data out of order is not supported in this archive format: "
    1188             :                   "\"%s\" is required, but comes before \"%s\" in the archive file.",
    1189             :                   th->targetFile, filename);
    1190             : 
    1191             :         /* Header doesn't match, so read to next header */
    1192           0 :         len = ((th->fileLen + 511) & ~511); /* Padded length */
    1193           0 :         blks = len >> 9;      /* # of 512 byte blocks */
    1194             : 
    1195           0 :         for (i = 0; i < blks; i++)
    1196           0 :             _tarReadRaw(AH, &header[0], 512, NULL, ctx->tarFH);
    1197             : 
    1198           0 :         if (!_tarGetHeader(AH, th))
    1199           0 :             fatal("could not find header for file \"%s\" in tar archive", filename);
    1200             :     }
    1201             : 
    1202          42 :     ctx->tarNextMember = ctx->tarFHpos + ((th->fileLen + 511) & ~511);
    1203          42 :     th->pos = 0;
    1204             : 
    1205          42 :     return th;
    1206             : }
    1207             : 
    1208             : /* Read & verify a header */
    1209             : static int
    1210          42 : _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
    1211             : {
    1212          42 :     lclContext *ctx = (lclContext *) AH->formatData;
    1213             :     char        h[512];
    1214             :     char        tag[100 + 1];
    1215             :     int         sum,
    1216             :                 chk;
    1217             :     pgoff_t     len;
    1218             :     pgoff_t     hPos;
    1219          42 :     bool        gotBlock = false;
    1220             : 
    1221          84 :     while (!gotBlock)
    1222             :     {
    1223             :         /* Save the pos for reporting purposes */
    1224          42 :         hPos = ctx->tarFHpos;
    1225             : 
    1226             :         /* Read a 512 byte block, return EOF, exit if short */
    1227          42 :         len = _tarReadRaw(AH, h, 512, NULL, ctx->tarFH);
    1228          42 :         if (len == 0)           /* EOF */
    1229           0 :             return 0;
    1230             : 
    1231          42 :         if (len != 512)
    1232           0 :             fatal(ngettext("incomplete tar header found (%lu byte)",
    1233             :                            "incomplete tar header found (%lu bytes)",
    1234             :                            len),
    1235             :                   (unsigned long) len);
    1236             : 
    1237             :         /* Calc checksum */
    1238          42 :         chk = tarChecksum(h);
    1239          42 :         sum = read_tar_number(&h[148], 8);
    1240             : 
    1241             :         /*
    1242             :          * If the checksum failed, see if it is a null block. If so, silently
    1243             :          * continue to the next block.
    1244             :          */
    1245          42 :         if (chk == sum)
    1246          42 :             gotBlock = true;
    1247             :         else
    1248             :         {
    1249             :             int         i;
    1250             : 
    1251           0 :             for (i = 0; i < 512; i++)
    1252             :             {
    1253           0 :                 if (h[i] != 0)
    1254             :                 {
    1255           0 :                     gotBlock = true;
    1256           0 :                     break;
    1257             :                 }
    1258             :             }
    1259             :         }
    1260             :     }
    1261             : 
    1262             :     /* Name field is 100 bytes, might not be null-terminated */
    1263          42 :     strlcpy(tag, &h[0], 100 + 1);
    1264             : 
    1265          42 :     len = read_tar_number(&h[124], 12);
    1266             : 
    1267             :     {
    1268             :         char        posbuf[32];
    1269             :         char        lenbuf[32];
    1270             : 
    1271          42 :         snprintf(posbuf, sizeof(posbuf), UINT64_FORMAT, (uint64) hPos);
    1272          42 :         snprintf(lenbuf, sizeof(lenbuf), UINT64_FORMAT, (uint64) len);
    1273          42 :         pg_log_debug("TOC Entry %s at %s (length %s, checksum %d)",
    1274             :                      tag, posbuf, lenbuf, sum);
    1275             :     }
    1276             : 
    1277          42 :     if (chk != sum)
    1278             :     {
    1279             :         char        posbuf[32];
    1280             : 
    1281           0 :         snprintf(posbuf, sizeof(posbuf), UINT64_FORMAT,
    1282           0 :                  (uint64) ftello(ctx->tarFH));
    1283           0 :         fatal("corrupt tar header found in %s (expected %d, computed %d) file position %s",
    1284             :               tag, sum, chk, posbuf);
    1285             :     }
    1286             : 
    1287          42 :     th->targetFile = pg_strdup(tag);
    1288          42 :     th->fileLen = len;
    1289             : 
    1290          42 :     return 1;
    1291             : }
    1292             : 
    1293             : 
    1294             : static void
    1295          46 : _tarWriteHeader(TAR_MEMBER *th)
    1296             : {
    1297             :     char        h[512];
    1298             : 
    1299          46 :     tarCreateHeader(h, th->targetFile, NULL, th->fileLen,
    1300             :                     0600, 04000, 02000, time(NULL));
    1301             : 
    1302             :     /* Now write the completed header. */
    1303          46 :     if (fwrite(h, 1, 512, th->tarFH) != 512)
    1304           0 :         WRITE_ERROR_EXIT;
    1305          46 : }

Generated by: LCOV version 1.13