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

Generated by: LCOV version 1.14