LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_backup_tar.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 368 453 81.2 %
Date: 2019-11-15 23:07:02 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           8 :             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           8 :             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         424 : _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
     250             : {
     251             :     lclTocEntry *ctx;
     252             :     char        fn[K_STD_BUF_SIZE];
     253             : 
     254         424 :     ctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
     255         424 :     if (te->dataDumper != NULL)
     256             :     {
     257             : #ifdef HAVE_LIBZ
     258          34 :         if (AH->compression == 0)
     259          34 :             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          34 :         ctx->filename = pg_strdup(fn);
     266             :     }
     267             :     else
     268             :     {
     269         390 :         ctx->filename = NULL;
     270         390 :         ctx->TH = NULL;
     271             :     }
     272         424 :     te->formatData = (void *) ctx;
     273         424 : }
     274             : 
     275             : static void
     276         424 : _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
     277             : {
     278         424 :     lclTocEntry *ctx = (lclTocEntry *) te->formatData;
     279             : 
     280         424 :     if (ctx->filename)
     281          34 :         WriteStr(AH, ctx->filename);
     282             :     else
     283         390 :         WriteStr(AH, "");
     284         424 : }
     285             : 
     286             : static void
     287         424 : _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
     288             : {
     289         424 :     lclTocEntry *ctx = (lclTocEntry *) te->formatData;
     290             : 
     291         424 :     if (ctx == NULL)
     292             :     {
     293         424 :         ctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
     294         424 :         te->formatData = (void *) ctx;
     295             :     }
     296             : 
     297         424 :     ctx->filename = ReadStr(AH);
     298         424 :     if (strlen(ctx->filename) == 0)
     299             :     {
     300         390 :         free(ctx->filename);
     301         390 :         ctx->filename = NULL;
     302             :     }
     303         424 :     ctx->TH = NULL;
     304         424 : }
     305             : 
     306             : static void
     307         816 : _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
     308             : {
     309         816 :     lclTocEntry *ctx = (lclTocEntry *) te->formatData;
     310             : 
     311         816 :     if (AH->public.verbose && ctx->filename != NULL)
     312           0 :         ahprintf(AH, "-- File: %s\n", ctx->filename);
     313         816 : }
     314             : 
     315             : static void
     316          32 : _StartData(ArchiveHandle *AH, TocEntry *te)
     317             : {
     318          32 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     319             : 
     320          32 :     tctx->TH = tarOpen(AH, tctx->filename, 'w');
     321          32 : }
     322             : 
     323             : static TAR_MEMBER *
     324          84 : tarOpen(ArchiveHandle *AH, const char *filename, char mode)
     325             : {
     326          84 :     lclContext *ctx = (lclContext *) AH->formatData;
     327             :     TAR_MEMBER *tm;
     328             : 
     329             : #ifdef HAVE_LIBZ
     330             :     char        fmode[14];
     331             : #endif
     332             : 
     333          84 :     if (mode == 'r')
     334             :     {
     335          40 :         tm = _tarPositionTo(AH, filename);
     336          40 :         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          40 :         if (AH->compression == 0)
     356          40 :             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          44 :         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          44 :         old_umask = umask(S_IRWXG | S_IRWXO);
     377             : 
     378             : #ifndef WIN32
     379          44 :         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          44 :         if (tm->tmpFH == NULL)
     410           0 :             fatal("could not generate temporary file name: %m");
     411             : 
     412          44 :         umask(old_umask);
     413             : 
     414             : #ifdef HAVE_LIBZ
     415             : 
     416          44 :         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          44 :             tm->nFH = tm->tmpFH;
     425             : #else
     426             : 
     427             :         tm->nFH = tm->tmpFH;
     428             : #endif
     429             : 
     430          44 :         tm->AH = AH;
     431          44 :         tm->targetFile = pg_strdup(filename);
     432             :     }
     433             : 
     434          84 :     tm->mode = mode;
     435          84 :     tm->tarFH = ctx->tarFH;
     436             : 
     437          84 :     return tm;
     438             : }
     439             : 
     440             : static void
     441          84 : tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
     442             : {
     443             :     /*
     444             :      * Close the GZ file since we dup'd. This will flush the buffers.
     445             :      */
     446          84 :     if (AH->compression != 0)
     447           0 :         if (GZCLOSE(th->zFH) != 0)
     448           0 :             fatal("could not close tar member");
     449             : 
     450          84 :     if (th->mode == 'w')
     451          44 :         _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          84 :     if (th->targetFile)
     459          84 :         free(th->targetFile);
     460             : 
     461          84 :     th->nFH = NULL;
     462          84 :     th->zFH = NULL;
     463          84 : }
     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       59120 : _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
     512             : {
     513       59120 :     lclContext *ctx = (lclContext *) AH->formatData;
     514             :     size_t      avail;
     515       59120 :     size_t      used = 0;
     516       59120 :     size_t      res = 0;
     517             : 
     518       59120 :     avail = AH->lookaheadLen - AH->lookaheadPos;
     519       59120 :     if (avail > 0)
     520             :     {
     521             :         /* We have some lookahead bytes to use */
     522           0 :         if (avail >= len)        /* Just use the lookahead buffer */
     523           0 :             used = len;
     524             :         else
     525           0 :             used = avail;
     526             : 
     527             :         /* Copy, and adjust buffer pos */
     528           0 :         memcpy(buf, AH->lookahead + AH->lookaheadPos, used);
     529           0 :         AH->lookaheadPos += used;
     530             : 
     531             :         /* Adjust required length */
     532           0 :         len -= used;
     533             :     }
     534             : 
     535             :     /* Read the file if len > 0 */
     536       59120 :     if (len > 0)
     537             :     {
     538       59120 :         if (fh)
     539             :         {
     540       16174 :             res = fread(&((char *) buf)[used], 1, len, fh);
     541       16174 :             if (res != len && !feof(fh))
     542           0 :                 READ_ERROR_EXIT(fh);
     543             :         }
     544       42946 :         else if (th)
     545             :         {
     546       42946 :             if (th->zFH)
     547             :             {
     548           0 :                 res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);
     549           0 :                 if (res != len && !GZEOF(th->zFH))
     550             :                 {
     551             : #ifdef HAVE_LIBZ
     552             :                     int         errnum;
     553           0 :                     const char *errmsg = gzerror(th->zFH, &errnum);
     554             : 
     555           0 :                     fatal("could not read from input file: %s",
     556             :                           errnum == Z_ERRNO ? strerror(errno) : errmsg);
     557             : #else
     558             :                     fatal("could not read from input file: %s",
     559             :                           strerror(errno));
     560             : #endif
     561             :                 }
     562             :             }
     563             :             else
     564             :             {
     565       42946 :                 res = fread(&((char *) buf)[used], 1, len, th->nFH);
     566       42946 :                 if (res != len && !feof(th->nFH))
     567           0 :                     READ_ERROR_EXIT(th->nFH);
     568             :             }
     569             :         }
     570             :         else
     571           0 :             fatal("internal error -- neither th nor fh specified in _tarReadRaw()");
     572             :     }
     573             : 
     574       59120 :     ctx->tarFHpos += res + used;
     575             : 
     576       59120 :     return (res + used);
     577             : }
     578             : 
     579             : static size_t
     580       43448 : tarRead(void *buf, size_t len, TAR_MEMBER *th)
     581             : {
     582             :     size_t      res;
     583             : 
     584       43448 :     if (th->pos + len > th->fileLen)
     585          68 :         len = th->fileLen - th->pos;
     586             : 
     587       43448 :     if (len <= 0)
     588         502 :         return 0;
     589             : 
     590       42946 :     res = _tarReadRaw(th->AH, buf, len, th, NULL);
     591             : 
     592       42946 :     th->pos += res;
     593             : 
     594       42946 :     return res;
     595             : }
     596             : 
     597             : static size_t
     598       45900 : tarWrite(const void *buf, size_t len, TAR_MEMBER *th)
     599             : {
     600             :     size_t      res;
     601             : 
     602       45900 :     if (th->zFH != NULL)
     603           0 :         res = GZWRITE(buf, 1, len, th->zFH);
     604             :     else
     605       45900 :         res = fwrite(buf, 1, len, th->nFH);
     606             : 
     607       45900 :     th->pos += res;
     608       45900 :     return res;
     609             : }
     610             : 
     611             : static void
     612          90 : _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
     613             : {
     614          90 :     lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
     615             : 
     616          90 :     if (tarWrite(data, dLen, tctx->TH) != dLen)
     617           0 :         WRITE_ERROR_EXIT;
     618             : 
     619          90 :     return;
     620             : }
     621             : 
     622             : static void
     623          32 : _EndData(ArchiveHandle *AH, TocEntry *te)
     624             : {
     625          32 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     626             : 
     627             :     /* Close the file */
     628          32 :     tarClose(AH, tctx->TH);
     629          32 :     tctx->TH = NULL;
     630          32 : }
     631             : 
     632             : /*
     633             :  * Print data for a given file
     634             :  */
     635             : static void
     636          32 : _PrintFileData(ArchiveHandle *AH, char *filename)
     637             : {
     638          32 :     lclContext *ctx = (lclContext *) AH->formatData;
     639             :     char        buf[4096];
     640             :     size_t      cnt;
     641             :     TAR_MEMBER *th;
     642             : 
     643          32 :     if (!filename)
     644           0 :         return;
     645             : 
     646          32 :     th = tarOpen(AH, filename, 'r');
     647          32 :     ctx->FH = th;
     648             : 
     649          96 :     while ((cnt = tarRead(buf, 4095, th)) > 0)
     650             :     {
     651          32 :         buf[cnt] = '\0';
     652          32 :         ahwrite(buf, 1, cnt, AH);
     653             :     }
     654             : 
     655          32 :     tarClose(AH, th);
     656             : }
     657             : 
     658             : 
     659             : /*
     660             :  * Print data for a given TOC entry
     661             : */
     662             : static void
     663          68 : _PrintTocData(ArchiveHandle *AH, TocEntry *te)
     664             : {
     665          68 :     lclContext *ctx = (lclContext *) AH->formatData;
     666          68 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     667             :     int         pos1;
     668             : 
     669          68 :     if (!tctx->filename)
     670           0 :         return;
     671             : 
     672             :     /*
     673             :      * If we're writing the special restore.sql script, emit a suitable
     674             :      * command to include each table's data from the corresponding file.
     675             :      *
     676             :      * In the COPY case this is a bit klugy because the regular COPY command
     677             :      * was already printed before we get control.
     678             :      */
     679          68 :     if (ctx->isSpecialScript)
     680             :     {
     681          34 :         if (te->copyStmt)
     682             :         {
     683             :             /* Abort the COPY FROM stdin */
     684          32 :             ahprintf(AH, "\\.\n");
     685             : 
     686             :             /*
     687             :              * The COPY statement should look like "COPY ... FROM stdin;\n",
     688             :              * see dumpTableData().
     689             :              */
     690          32 :             pos1 = (int) strlen(te->copyStmt) - 13;
     691          64 :             if (pos1 < 6 || strncmp(te->copyStmt, "COPY ", 5) != 0 ||
     692          32 :                 strcmp(te->copyStmt + pos1, " FROM stdin;\n") != 0)
     693           0 :                 fatal("unexpected COPY statement syntax: \"%s\"",
     694             :                       te->copyStmt);
     695             : 
     696             :             /* Emit all but the FROM part ... */
     697          32 :             ahwrite(te->copyStmt, 1, pos1, AH);
     698             :             /* ... and insert modified FROM */
     699          32 :             ahprintf(AH, " FROM '$$PATH$$/%s';\n\n", tctx->filename);
     700             :         }
     701             :         else
     702             :         {
     703             :             /* --inserts mode, no worries, just include the data file */
     704           2 :             ahprintf(AH, "\\i $$PATH$$/%s\n\n", tctx->filename);
     705             :         }
     706             : 
     707          34 :         return;
     708             :     }
     709             : 
     710          34 :     if (strcmp(te->desc, "BLOBS") == 0)
     711           2 :         _LoadBlobs(AH);
     712             :     else
     713          32 :         _PrintFileData(AH, tctx->filename);
     714             : }
     715             : 
     716             : static void
     717           2 : _LoadBlobs(ArchiveHandle *AH)
     718             : {
     719             :     Oid         oid;
     720           2 :     lclContext *ctx = (lclContext *) AH->formatData;
     721             :     TAR_MEMBER *th;
     722             :     size_t      cnt;
     723           2 :     bool        foundBlob = false;
     724             :     char        buf[4096];
     725             : 
     726           2 :     StartRestoreBlobs(AH);
     727             : 
     728           2 :     th = tarOpen(AH, NULL, 'r');    /* Open next file */
     729           6 :     while (th != NULL)
     730             :     {
     731           4 :         ctx->FH = th;
     732             : 
     733           4 :         if (strncmp(th->targetFile, "blob_", 5) == 0)
     734             :         {
     735           2 :             oid = atooid(&th->targetFile[5]);
     736           2 :             if (oid != 0)
     737             :             {
     738           2 :                 pg_log_info("restoring large object with OID %u", oid);
     739             : 
     740           2 :                 StartRestoreBlob(AH, oid, AH->public.ropt->dropSchema);
     741             : 
     742           6 :                 while ((cnt = tarRead(buf, 4095, th)) > 0)
     743             :                 {
     744           2 :                     buf[cnt] = '\0';
     745           2 :                     ahwrite(buf, 1, cnt, AH);
     746             :                 }
     747           2 :                 EndRestoreBlob(AH, oid);
     748           2 :                 foundBlob = true;
     749             :             }
     750           2 :             tarClose(AH, th);
     751             :         }
     752             :         else
     753             :         {
     754           2 :             tarClose(AH, th);
     755             : 
     756             :             /*
     757             :              * Once we have found the first blob, stop at the first non-blob
     758             :              * entry (which will be 'blobs.toc').  This coding would eat all
     759             :              * the rest of the archive if there are no blobs ... but this
     760             :              * function shouldn't be called at all in that case.
     761             :              */
     762           2 :             if (foundBlob)
     763           2 :                 break;
     764             :         }
     765             : 
     766           2 :         th = tarOpen(AH, NULL, 'r');
     767             :     }
     768           2 :     EndRestoreBlobs(AH);
     769           2 : }
     770             : 
     771             : 
     772             : static int
     773       38844 : _WriteByte(ArchiveHandle *AH, const int i)
     774             : {
     775       38844 :     lclContext *ctx = (lclContext *) AH->formatData;
     776       38844 :     char        b = i;          /* Avoid endian problems */
     777             : 
     778       38844 :     if (tarWrite(&b, 1, ctx->FH) != 1)
     779           0 :         WRITE_ERROR_EXIT;
     780             : 
     781       38844 :     ctx->filePos += 1;
     782       38844 :     return 1;
     783             : }
     784             : 
     785             : static int
     786       38844 : _ReadByte(ArchiveHandle *AH)
     787             : {
     788       38844 :     lclContext *ctx = (lclContext *) AH->formatData;
     789             :     size_t      res;
     790             :     unsigned char c;
     791             : 
     792       38844 :     res = tarRead(&c, 1, ctx->FH);
     793       38844 :     if (res != 1)
     794             :         /* We already would have exited for errors on reads, must be EOF */
     795           0 :         fatal("could not read from input file: end of file");
     796       38844 :     ctx->filePos += 1;
     797       38844 :     return c;
     798             : }
     799             : 
     800             : static void
     801        4536 : _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
     802             : {
     803        4536 :     lclContext *ctx = (lclContext *) AH->formatData;
     804             : 
     805        4536 :     if (tarWrite(buf, len, ctx->FH) != len)
     806           0 :         WRITE_ERROR_EXIT;
     807             : 
     808        4536 :     ctx->filePos += len;
     809        4536 : }
     810             : 
     811             : static void
     812        4536 : _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
     813             : {
     814        4536 :     lclContext *ctx = (lclContext *) AH->formatData;
     815             : 
     816        4536 :     if (tarRead(buf, len, ctx->FH) != len)
     817             :         /* We already would have exited for errors on reads, must be EOF */
     818           0 :         fatal("could not read from input file: end of file");
     819             : 
     820        4536 :     ctx->filePos += len;
     821        4536 :     return;
     822             : }
     823             : 
     824             : static void
     825           8 : _CloseArchive(ArchiveHandle *AH)
     826             : {
     827           8 :     lclContext *ctx = (lclContext *) AH->formatData;
     828             :     TAR_MEMBER *th;
     829             :     RestoreOptions *ropt;
     830             :     RestoreOptions *savRopt;
     831             :     DumpOptions *savDopt;
     832             :     int         savVerbose,
     833             :                 i;
     834             : 
     835           8 :     if (AH->mode == archModeWrite)
     836             :     {
     837             :         /*
     838             :          * Write the Header & TOC to the archive FIRST
     839             :          */
     840           4 :         th = tarOpen(AH, "toc.dat", 'w');
     841           4 :         ctx->FH = th;
     842           4 :         WriteHead(AH);
     843           4 :         WriteToc(AH);
     844           4 :         tarClose(AH, th);       /* Not needed any more */
     845             : 
     846             :         /*
     847             :          * Now send the data (tables & blobs)
     848             :          */
     849           4 :         WriteDataChunks(AH, NULL);
     850             : 
     851             :         /*
     852             :          * Now this format wants to append a script which does a full restore
     853             :          * if the files have been extracted.
     854             :          */
     855           4 :         th = tarOpen(AH, "restore.sql", 'w');
     856             : 
     857           4 :         tarPrintf(AH, th, "--\n"
     858             :                   "-- NOTE:\n"
     859             :                   "--\n"
     860             :                   "-- File paths need to be edited. Search for $$PATH$$ and\n"
     861             :                   "-- replace it with the path to the directory containing\n"
     862             :                   "-- the extracted data files.\n"
     863             :                   "--\n");
     864             : 
     865           4 :         AH->CustomOutPtr = _scriptOut;
     866             : 
     867           4 :         ctx->isSpecialScript = 1;
     868           4 :         ctx->scriptTH = th;
     869             : 
     870           4 :         ropt = NewRestoreOptions();
     871           4 :         memcpy(ropt, AH->public.ropt, sizeof(RestoreOptions));
     872           4 :         ropt->filename = NULL;
     873           4 :         ropt->dropSchema = 1;
     874           4 :         ropt->compression = 0;
     875           4 :         ropt->superuser = NULL;
     876           4 :         ropt->suppressDumpWarnings = true;
     877             : 
     878           4 :         savDopt = AH->public.dopt;
     879           4 :         savRopt = AH->public.ropt;
     880             : 
     881           4 :         SetArchiveOptions((Archive *) AH, NULL, ropt);
     882             : 
     883           4 :         savVerbose = AH->public.verbose;
     884           4 :         AH->public.verbose = 0;
     885             : 
     886           4 :         RestoreArchive((Archive *) AH);
     887             : 
     888           4 :         SetArchiveOptions((Archive *) AH, savDopt, savRopt);
     889             : 
     890           4 :         AH->public.verbose = savVerbose;
     891             : 
     892           4 :         tarClose(AH, th);
     893             : 
     894           4 :         ctx->isSpecialScript = 0;
     895             : 
     896             :         /*
     897             :          * EOF marker for tar files is two blocks of NULLs.
     898             :          */
     899        4100 :         for (i = 0; i < 512 * 2; i++)
     900             :         {
     901        4096 :             if (fputc(0, ctx->tarFH) == EOF)
     902           0 :                 WRITE_ERROR_EXIT;
     903             :         }
     904             : 
     905             :         /* Sync the output file if one is defined */
     906           4 :         if (AH->dosync && AH->fSpec)
     907           2 :             (void) fsync_fname(AH->fSpec, false);
     908             :     }
     909             : 
     910           8 :     AH->FH = NULL;
     911           8 : }
     912             : 
     913             : static size_t
     914        2424 : _scriptOut(ArchiveHandle *AH, const void *buf, size_t len)
     915             : {
     916        2424 :     lclContext *ctx = (lclContext *) AH->formatData;
     917             : 
     918        2424 :     return tarWrite(buf, len, ctx->scriptTH);
     919             : }
     920             : 
     921             : /*
     922             :  * BLOB support
     923             :  */
     924             : 
     925             : /*
     926             :  * Called by the archiver when starting to save all BLOB DATA (not schema).
     927             :  * This routine should save whatever format-specific information is needed
     928             :  * to read the BLOBs back into memory.
     929             :  *
     930             :  * It is called just prior to the dumper's DataDumper routine.
     931             :  *
     932             :  * Optional, but strongly recommended.
     933             :  *
     934             :  */
     935             : static void
     936           2 : _StartBlobs(ArchiveHandle *AH, TocEntry *te)
     937             : {
     938           2 :     lclContext *ctx = (lclContext *) AH->formatData;
     939             :     char        fname[K_STD_BUF_SIZE];
     940             : 
     941           2 :     sprintf(fname, "blobs.toc");
     942           2 :     ctx->blobToc = tarOpen(AH, fname, 'w');
     943           2 : }
     944             : 
     945             : /*
     946             :  * Called by the archiver when the dumper calls StartBlob.
     947             :  *
     948             :  * Mandatory.
     949             :  *
     950             :  * Must save the passed OID for retrieval at restore-time.
     951             :  */
     952             : static void
     953           2 : _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
     954             : {
     955           2 :     lclContext *ctx = (lclContext *) AH->formatData;
     956           2 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     957             :     char        fname[255];
     958             :     char       *sfx;
     959             : 
     960           2 :     if (oid == 0)
     961           0 :         fatal("invalid OID for large object (%u)", oid);
     962             : 
     963           2 :     if (AH->compression != 0)
     964           0 :         sfx = ".gz";
     965             :     else
     966           2 :         sfx = "";
     967             : 
     968           2 :     sprintf(fname, "blob_%u.dat%s", oid, sfx);
     969             : 
     970           2 :     tarPrintf(AH, ctx->blobToc, "%u %s\n", oid, fname);
     971             : 
     972           2 :     tctx->TH = tarOpen(AH, fname, 'w');
     973           2 : }
     974             : 
     975             : /*
     976             :  * Called by the archiver when the dumper calls EndBlob.
     977             :  *
     978             :  * Optional.
     979             :  *
     980             :  */
     981             : static void
     982           2 : _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
     983             : {
     984           2 :     lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     985             : 
     986           2 :     tarClose(AH, tctx->TH);
     987           2 : }
     988             : 
     989             : /*
     990             :  * Called by the archiver when finishing saving all BLOB DATA.
     991             :  *
     992             :  * Optional.
     993             :  *
     994             :  */
     995             : static void
     996           2 : _EndBlobs(ArchiveHandle *AH, TocEntry *te)
     997             : {
     998           2 :     lclContext *ctx = (lclContext *) AH->formatData;
     999             : 
    1000             :     /* Write out a fake zero OID to mark end-of-blobs. */
    1001             :     /* WriteInt(AH, 0); */
    1002             : 
    1003           2 :     tarClose(AH, ctx->blobToc);
    1004           2 : }
    1005             : 
    1006             : 
    1007             : 
    1008             : /*------------
    1009             :  * TAR Support
    1010             :  *------------
    1011             :  */
    1012             : 
    1013             : static int
    1014           6 : tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...)
    1015             : {
    1016           6 :     int         save_errno = errno;
    1017             :     char       *p;
    1018           6 :     size_t      len = 128;      /* initial assumption about buffer size */
    1019             :     size_t      cnt;
    1020             : 
    1021             :     for (;;)
    1022           4 :     {
    1023             :         va_list     args;
    1024             : 
    1025             :         /* Allocate work buffer. */
    1026          10 :         p = (char *) pg_malloc(len);
    1027             : 
    1028             :         /* Try to format the data. */
    1029          10 :         errno = save_errno;
    1030          10 :         va_start(args, fmt);
    1031          10 :         cnt = pvsnprintf(p, len, fmt, args);
    1032          10 :         va_end(args);
    1033             : 
    1034          10 :         if (cnt < len)
    1035           6 :             break;              /* success */
    1036             : 
    1037             :         /* Release buffer and loop around to try again with larger len. */
    1038           4 :         free(p);
    1039           4 :         len = cnt;
    1040             :     }
    1041             : 
    1042           6 :     cnt = tarWrite(p, cnt, th);
    1043           6 :     free(p);
    1044          12 :     return (int) cnt;
    1045             : }
    1046             : 
    1047             : bool
    1048           2 : isValidTarHeader(char *header)
    1049             : {
    1050             :     int         sum;
    1051           2 :     int         chk = tarChecksum(header);
    1052             : 
    1053           2 :     sum = read_tar_number(&header[148], 8);
    1054             : 
    1055           2 :     if (sum != chk)
    1056           0 :         return false;
    1057             : 
    1058             :     /* POSIX tar format */
    1059           4 :     if (memcmp(&header[257], "ustar\0", 6) == 0 &&
    1060           2 :         memcmp(&header[263], "00", 2) == 0)
    1061           2 :         return true;
    1062             :     /* GNU tar format */
    1063           0 :     if (memcmp(&header[257], "ustar  \0", 8) == 0)
    1064           0 :         return true;
    1065             :     /* not-quite-POSIX format written by pre-9.3 pg_dump */
    1066           0 :     if (memcmp(&header[257], "ustar00\0", 8) == 0)
    1067           0 :         return true;
    1068             : 
    1069           0 :     return false;
    1070             : }
    1071             : 
    1072             : /* Given the member, write the TAR header & copy the file */
    1073             : static void
    1074          44 : _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
    1075             : {
    1076          44 :     lclContext *ctx = (lclContext *) AH->formatData;
    1077          44 :     FILE       *tmp = th->tmpFH; /* Grab it for convenience */
    1078             :     char        buf[32768];
    1079             :     size_t      cnt;
    1080          44 :     pgoff_t     len = 0;
    1081             :     size_t      res;
    1082             :     size_t      i,
    1083             :                 pad;
    1084             : 
    1085             :     /*
    1086             :      * Find file len & go back to start.
    1087             :      */
    1088          44 :     fseeko(tmp, 0, SEEK_END);
    1089          44 :     th->fileLen = ftello(tmp);
    1090          44 :     if (th->fileLen < 0)
    1091           0 :         fatal("could not determine seek position in archive file: %m");
    1092          44 :     fseeko(tmp, 0, SEEK_SET);
    1093             : 
    1094          44 :     _tarWriteHeader(th);
    1095             : 
    1096         136 :     while ((cnt = fread(buf, 1, sizeof(buf), tmp)) > 0)
    1097             :     {
    1098          48 :         if ((res = fwrite(buf, 1, cnt, th->tarFH)) != cnt)
    1099           0 :             WRITE_ERROR_EXIT;
    1100          48 :         len += res;
    1101             :     }
    1102          44 :     if (!feof(tmp))
    1103           0 :         READ_ERROR_EXIT(tmp);
    1104             : 
    1105          44 :     if (fclose(tmp) != 0)       /* This *should* delete it... */
    1106           0 :         fatal("could not close temporary file: %m");
    1107             : 
    1108          44 :     if (len != th->fileLen)
    1109             :     {
    1110             :         char        buf1[32],
    1111             :                     buf2[32];
    1112             : 
    1113           0 :         snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) len);
    1114           0 :         snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) th->fileLen);
    1115           0 :         fatal("actual file length (%s) does not match expected (%s)",
    1116             :               buf1, buf2);
    1117             :     }
    1118             : 
    1119          44 :     pad = ((len + 511) & ~511) - len;
    1120       19258 :     for (i = 0; i < pad; i++)
    1121             :     {
    1122       19214 :         if (fputc('\0', th->tarFH) == EOF)
    1123           0 :             WRITE_ERROR_EXIT;
    1124             :     }
    1125             : 
    1126          44 :     ctx->tarFHpos += len + pad;
    1127          44 : }
    1128             : 
    1129             : /* Locate the file in the archive, read header and position to data */
    1130             : static TAR_MEMBER *
    1131          40 : _tarPositionTo(ArchiveHandle *AH, const char *filename)
    1132             : {
    1133          40 :     lclContext *ctx = (lclContext *) AH->formatData;
    1134          40 :     TAR_MEMBER *th = pg_malloc0(sizeof(TAR_MEMBER));
    1135             :     char        c;
    1136             :     char        header[512];
    1137             :     size_t      i,
    1138             :                 len,
    1139             :                 blks;
    1140             :     int         id;
    1141             : 
    1142          40 :     th->AH = AH;
    1143             : 
    1144             :     /* Go to end of current file, if any */
    1145          40 :     if (ctx->tarFHpos != 0)
    1146             :     {
    1147             :         char        buf1[100],
    1148             :                     buf2[100];
    1149             : 
    1150          36 :         snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) ctx->tarFHpos);
    1151          36 :         snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) ctx->tarNextMember);
    1152          36 :         pg_log_debug("moving from position %s to next member at file position %s",
    1153             :                      buf1, buf2);
    1154             : 
    1155       16206 :         while (ctx->tarFHpos < ctx->tarNextMember)
    1156       16134 :             _tarReadRaw(AH, &c, 1, NULL, ctx->tarFH);
    1157             :     }
    1158             : 
    1159             :     {
    1160             :         char        buf[100];
    1161             : 
    1162          40 :         snprintf(buf, sizeof(buf), INT64_FORMAT, (int64) ctx->tarFHpos);
    1163          40 :         pg_log_debug("now at file position %s", buf);
    1164             :     }
    1165             : 
    1166             :     /* We are at the start of the file, or at the next member */
    1167             : 
    1168             :     /* Get the header */
    1169          40 :     if (!_tarGetHeader(AH, th))
    1170             :     {
    1171           0 :         if (filename)
    1172           0 :             fatal("could not find header for file \"%s\" in tar archive", filename);
    1173             :         else
    1174             :         {
    1175             :             /*
    1176             :              * We're just scanning the archive for the next file, so return
    1177             :              * null
    1178             :              */
    1179           0 :             free(th);
    1180           0 :             return NULL;
    1181             :         }
    1182             :     }
    1183             : 
    1184          80 :     while (filename != NULL && strcmp(th->targetFile, filename) != 0)
    1185             :     {
    1186           0 :         pg_log_debug("skipping tar member %s", th->targetFile);
    1187             : 
    1188           0 :         id = atoi(th->targetFile);
    1189           0 :         if ((TocIDRequired(AH, id) & REQ_DATA) != 0)
    1190           0 :             fatal("restoring data out of order is not supported in this archive format: "
    1191             :                   "\"%s\" is required, but comes before \"%s\" in the archive file.",
    1192             :                   th->targetFile, filename);
    1193             : 
    1194             :         /* Header doesn't match, so read to next header */
    1195           0 :         len = ((th->fileLen + 511) & ~511); /* Padded length */
    1196           0 :         blks = len >> 9;      /* # of 512 byte blocks */
    1197             : 
    1198           0 :         for (i = 0; i < blks; i++)
    1199           0 :             _tarReadRaw(AH, &header[0], 512, NULL, ctx->tarFH);
    1200             : 
    1201           0 :         if (!_tarGetHeader(AH, th))
    1202           0 :             fatal("could not find header for file \"%s\" in tar archive", filename);
    1203             :     }
    1204             : 
    1205          40 :     ctx->tarNextMember = ctx->tarFHpos + ((th->fileLen + 511) & ~511);
    1206          40 :     th->pos = 0;
    1207             : 
    1208          40 :     return th;
    1209             : }
    1210             : 
    1211             : /* Read & verify a header */
    1212             : static int
    1213          40 : _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
    1214             : {
    1215          40 :     lclContext *ctx = (lclContext *) AH->formatData;
    1216             :     char        h[512];
    1217             :     char        tag[100 + 1];
    1218             :     int         sum,
    1219             :                 chk;
    1220             :     pgoff_t     len;
    1221             :     pgoff_t     hPos;
    1222          40 :     bool        gotBlock = false;
    1223             : 
    1224         120 :     while (!gotBlock)
    1225             :     {
    1226             :         /* Save the pos for reporting purposes */
    1227          40 :         hPos = ctx->tarFHpos;
    1228             : 
    1229             :         /* Read a 512 byte block, return EOF, exit if short */
    1230          40 :         len = _tarReadRaw(AH, h, 512, NULL, ctx->tarFH);
    1231          40 :         if (len == 0)           /* EOF */
    1232           0 :             return 0;
    1233             : 
    1234          40 :         if (len != 512)
    1235           0 :             fatal(ngettext("incomplete tar header found (%lu byte)",
    1236             :                            "incomplete tar header found (%lu bytes)",
    1237             :                            len),
    1238             :                   (unsigned long) len);
    1239             : 
    1240             :         /* Calc checksum */
    1241          40 :         chk = tarChecksum(h);
    1242          40 :         sum = read_tar_number(&h[148], 8);
    1243             : 
    1244             :         /*
    1245             :          * If the checksum failed, see if it is a null block. If so, silently
    1246             :          * continue to the next block.
    1247             :          */
    1248          40 :         if (chk == sum)
    1249          40 :             gotBlock = true;
    1250             :         else
    1251             :         {
    1252             :             int         i;
    1253             : 
    1254           0 :             for (i = 0; i < 512; i++)
    1255             :             {
    1256           0 :                 if (h[i] != 0)
    1257             :                 {
    1258           0 :                     gotBlock = true;
    1259           0 :                     break;
    1260             :                 }
    1261             :             }
    1262             :         }
    1263             :     }
    1264             : 
    1265             :     /* Name field is 100 bytes, might not be null-terminated */
    1266          40 :     strlcpy(tag, &h[0], 100 + 1);
    1267             : 
    1268          40 :     len = read_tar_number(&h[124], 12);
    1269             : 
    1270             :     {
    1271             :         char        posbuf[32];
    1272             :         char        lenbuf[32];
    1273             : 
    1274          40 :         snprintf(posbuf, sizeof(posbuf), UINT64_FORMAT, (uint64) hPos);
    1275          40 :         snprintf(lenbuf, sizeof(lenbuf), UINT64_FORMAT, (uint64) len);
    1276          40 :         pg_log_debug("TOC Entry %s at %s (length %s, checksum %d)",
    1277             :                      tag, posbuf, lenbuf, sum);
    1278             :     }
    1279             : 
    1280          40 :     if (chk != sum)
    1281             :     {
    1282             :         char        posbuf[32];
    1283             : 
    1284           0 :         snprintf(posbuf, sizeof(posbuf), UINT64_FORMAT,
    1285           0 :                  (uint64) ftello(ctx->tarFH));
    1286           0 :         fatal("corrupt tar header found in %s (expected %d, computed %d) file position %s",
    1287             :               tag, sum, chk, posbuf);
    1288             :     }
    1289             : 
    1290          40 :     th->targetFile = pg_strdup(tag);
    1291          40 :     th->fileLen = len;
    1292             : 
    1293          40 :     return 1;
    1294             : }
    1295             : 
    1296             : 
    1297             : static void
    1298          44 : _tarWriteHeader(TAR_MEMBER *th)
    1299             : {
    1300             :     char        h[512];
    1301             : 
    1302          44 :     tarCreateHeader(h, th->targetFile, NULL, th->fileLen,
    1303             :                     0600, 04000, 02000, time(NULL));
    1304             : 
    1305             :     /* Now write the completed header. */
    1306          44 :     if (fwrite(h, 1, 512, th->tarFH) != 512)
    1307           0 :         WRITE_ERROR_EXIT;
    1308          44 : }

Generated by: LCOV version 1.13