LCOV - differential code coverage report
Current view: top level - src/bin/pg_dump - pg_backup_tar.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 83.7 % 430 360 9 35 26 13 147 31 169 31 160 22
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 32 32 19 10 3 24
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 100.0 % 25 25 25
Legend: Lines: hit not hit (180,240] days: 100.0 % 5 5 5
(240..) days: 82.5 % 400 330 9 35 26 13 147 1 169 31 160
Function coverage date bins:
(120,180] days: 100.0 % 5 5 5
(240..) days: 52.9 % 51 27 19 5 3 24

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

Generated by: LCOV version v1.16-55-g56c0a2a