LCOV - code coverage report
Current view: top level - src/backend/backup - basebackup.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 558 663 84.2 %
Date: 2024-11-21 08:14:44 Functions: 14 15 93.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * basebackup.c
       4             :  *    code for taking a base backup and streaming it to a standby
       5             :  *
       6             :  * Portions Copyright (c) 2010-2024, PostgreSQL Global Development Group
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *    src/backend/backup/basebackup.c
      10             :  *
      11             :  *-------------------------------------------------------------------------
      12             :  */
      13             : #include "postgres.h"
      14             : 
      15             : #include <sys/stat.h>
      16             : #include <unistd.h>
      17             : #include <time.h>
      18             : 
      19             : #include "access/xlog_internal.h"
      20             : #include "access/xlogbackup.h"
      21             : #include "backup/backup_manifest.h"
      22             : #include "backup/basebackup.h"
      23             : #include "backup/basebackup_incremental.h"
      24             : #include "backup/basebackup_sink.h"
      25             : #include "backup/basebackup_target.h"
      26             : #include "catalog/pg_tablespace_d.h"
      27             : #include "commands/defrem.h"
      28             : #include "common/compression.h"
      29             : #include "common/file_perm.h"
      30             : #include "common/file_utils.h"
      31             : #include "lib/stringinfo.h"
      32             : #include "miscadmin.h"
      33             : #include "nodes/pg_list.h"
      34             : #include "pgstat.h"
      35             : #include "pgtar.h"
      36             : #include "postmaster/syslogger.h"
      37             : #include "postmaster/walsummarizer.h"
      38             : #include "replication/slot.h"
      39             : #include "replication/walsender.h"
      40             : #include "replication/walsender_private.h"
      41             : #include "storage/bufpage.h"
      42             : #include "storage/checksum.h"
      43             : #include "storage/dsm_impl.h"
      44             : #include "storage/ipc.h"
      45             : #include "storage/reinit.h"
      46             : #include "utils/builtins.h"
      47             : #include "utils/guc.h"
      48             : #include "utils/ps_status.h"
      49             : #include "utils/relcache.h"
      50             : #include "utils/resowner.h"
      51             : 
      52             : /*
      53             :  * How much data do we want to send in one CopyData message? Note that
      54             :  * this may also result in reading the underlying files in chunks of this
      55             :  * size.
      56             :  *
      57             :  * NB: The buffer size is required to be a multiple of the system block
      58             :  * size, so use that value instead if it's bigger than our preference.
      59             :  */
      60             : #define SINK_BUFFER_LENGTH          Max(32768, BLCKSZ)
      61             : 
      62             : typedef struct
      63             : {
      64             :     const char *label;
      65             :     bool        progress;
      66             :     bool        fastcheckpoint;
      67             :     bool        nowait;
      68             :     bool        includewal;
      69             :     bool        incremental;
      70             :     uint32      maxrate;
      71             :     bool        sendtblspcmapfile;
      72             :     bool        send_to_client;
      73             :     bool        use_copytblspc;
      74             :     BaseBackupTargetHandle *target_handle;
      75             :     backup_manifest_option manifest;
      76             :     pg_compress_algorithm compression;
      77             :     pg_compress_specification compression_specification;
      78             :     pg_checksum_type manifest_checksum_type;
      79             : } basebackup_options;
      80             : 
      81             : static int64 sendTablespace(bbsink *sink, char *path, Oid spcoid, bool sizeonly,
      82             :                             struct backup_manifest_info *manifest,
      83             :                             IncrementalBackupInfo *ib);
      84             : static int64 sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
      85             :                      List *tablespaces, bool sendtblspclinks,
      86             :                      backup_manifest_info *manifest, Oid spcoid,
      87             :                      IncrementalBackupInfo *ib);
      88             : static bool sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
      89             :                      struct stat *statbuf, bool missing_ok,
      90             :                      Oid dboid, Oid spcoid, RelFileNumber relfilenumber,
      91             :                      unsigned segno,
      92             :                      backup_manifest_info *manifest,
      93             :                      unsigned num_incremental_blocks,
      94             :                      BlockNumber *incremental_blocks,
      95             :                      unsigned truncation_block_length);
      96             : static off_t read_file_data_into_buffer(bbsink *sink,
      97             :                                         const char *readfilename, int fd,
      98             :                                         off_t offset, size_t length,
      99             :                                         BlockNumber blkno,
     100             :                                         bool verify_checksum,
     101             :                                         int *checksum_failures);
     102             : static void push_to_sink(bbsink *sink, pg_checksum_context *checksum_ctx,
     103             :                          size_t *bytes_done, void *data, size_t length);
     104             : static bool verify_page_checksum(Page page, XLogRecPtr start_lsn,
     105             :                                  BlockNumber blkno,
     106             :                                  uint16 *expected_checksum);
     107             : static void sendFileWithContent(bbsink *sink, const char *filename,
     108             :                                 const char *content, int len,
     109             :                                 backup_manifest_info *manifest);
     110             : static int64 _tarWriteHeader(bbsink *sink, const char *filename,
     111             :                              const char *linktarget, struct stat *statbuf,
     112             :                              bool sizeonly);
     113             : static void _tarWritePadding(bbsink *sink, int len);
     114             : static void convert_link_to_directory(const char *pathbuf, struct stat *statbuf);
     115             : static void perform_base_backup(basebackup_options *opt, bbsink *sink,
     116             :                                 IncrementalBackupInfo *ib);
     117             : static void parse_basebackup_options(List *options, basebackup_options *opt);
     118             : static int  compareWalFileNames(const ListCell *a, const ListCell *b);
     119             : static ssize_t basebackup_read_file(int fd, char *buf, size_t nbytes, off_t offset,
     120             :                                     const char *filename, bool partial_read_ok);
     121             : 
     122             : /* Was the backup currently in-progress initiated in recovery mode? */
     123             : static bool backup_started_in_recovery = false;
     124             : 
     125             : /* Total number of checksum failures during base backup. */
     126             : static long long int total_checksum_failures;
     127             : 
     128             : /* Do not verify checksums. */
     129             : static bool noverify_checksums = false;
     130             : 
     131             : /*
     132             :  * Definition of one element part of an exclusion list, used for paths part
     133             :  * of checksum validation or base backups.  "name" is the name of the file
     134             :  * or path to check for exclusion.  If "match_prefix" is true, any items
     135             :  * matching the name as prefix are excluded.
     136             :  */
     137             : struct exclude_list_item
     138             : {
     139             :     const char *name;
     140             :     bool        match_prefix;
     141             : };
     142             : 
     143             : /*
     144             :  * The contents of these directories are removed or recreated during server
     145             :  * start so they are not included in backups.  The directories themselves are
     146             :  * kept and included as empty to preserve access permissions.
     147             :  *
     148             :  * Note: this list should be kept in sync with the filter lists in pg_rewind's
     149             :  * filemap.c.
     150             :  */
     151             : static const char *const excludeDirContents[] =
     152             : {
     153             :     /*
     154             :      * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped
     155             :      * because extensions like pg_stat_statements store data there.
     156             :      */
     157             :     PG_STAT_TMP_DIR,
     158             : 
     159             :     /*
     160             :      * It is generally not useful to backup the contents of this directory
     161             :      * even if the intention is to restore to another primary. See backup.sgml
     162             :      * for a more detailed description.
     163             :      */
     164             :     PG_REPLSLOT_DIR,
     165             : 
     166             :     /* Contents removed on startup, see dsm_cleanup_for_mmap(). */
     167             :     PG_DYNSHMEM_DIR,
     168             : 
     169             :     /* Contents removed on startup, see AsyncShmemInit(). */
     170             :     "pg_notify",
     171             : 
     172             :     /*
     173             :      * Old contents are loaded for possible debugging but are not required for
     174             :      * normal operation, see SerialInit().
     175             :      */
     176             :     "pg_serial",
     177             : 
     178             :     /* Contents removed on startup, see DeleteAllExportedSnapshotFiles(). */
     179             :     "pg_snapshots",
     180             : 
     181             :     /* Contents zeroed on startup, see StartupSUBTRANS(). */
     182             :     "pg_subtrans",
     183             : 
     184             :     /* end of list */
     185             :     NULL
     186             : };
     187             : 
     188             : /*
     189             :  * List of files excluded from backups.
     190             :  */
     191             : static const struct exclude_list_item excludeFiles[] =
     192             : {
     193             :     /* Skip auto conf temporary file. */
     194             :     {PG_AUTOCONF_FILENAME ".tmp", false},
     195             : 
     196             :     /* Skip current log file temporary file */
     197             :     {LOG_METAINFO_DATAFILE_TMP, false},
     198             : 
     199             :     /*
     200             :      * Skip relation cache because it is rebuilt on startup.  This includes
     201             :      * temporary files.
     202             :      */
     203             :     {RELCACHE_INIT_FILENAME, true},
     204             : 
     205             :     /*
     206             :      * backup_label and tablespace_map should not exist in a running cluster
     207             :      * capable of doing an online backup, but exclude them just in case.
     208             :      */
     209             :     {BACKUP_LABEL_FILE, false},
     210             :     {TABLESPACE_MAP, false},
     211             : 
     212             :     /*
     213             :      * If there's a backup_manifest, it belongs to a backup that was used to
     214             :      * start this server. It is *not* correct for this backup. Our
     215             :      * backup_manifest is injected into the backup separately if users want
     216             :      * it.
     217             :      */
     218             :     {"backup_manifest", false},
     219             : 
     220             :     {"postmaster.pid", false},
     221             :     {"postmaster.opts", false},
     222             : 
     223             :     /* end of list */
     224             :     {NULL, false}
     225             : };
     226             : 
     227             : /*
     228             :  * Actually do a base backup for the specified tablespaces.
     229             :  *
     230             :  * This is split out mainly to avoid complaints about "variable might be
     231             :  * clobbered by longjmp" from stupider versions of gcc.
     232             :  */
     233             : static void
     234         312 : perform_base_backup(basebackup_options *opt, bbsink *sink,
     235             :                     IncrementalBackupInfo *ib)
     236             : {
     237             :     bbsink_state state;
     238             :     XLogRecPtr  endptr;
     239             :     TimeLineID  endtli;
     240             :     backup_manifest_info manifest;
     241             :     BackupState *backup_state;
     242             :     StringInfo  tablespace_map;
     243             : 
     244             :     /* Initial backup state, insofar as we know it now. */
     245         312 :     state.tablespaces = NIL;
     246         312 :     state.tablespace_num = 0;
     247         312 :     state.bytes_done = 0;
     248         312 :     state.bytes_total = 0;
     249         312 :     state.bytes_total_is_valid = false;
     250             : 
     251             :     /* we're going to use a BufFile, so we need a ResourceOwner */
     252             :     Assert(AuxProcessResourceOwner != NULL);
     253             :     Assert(CurrentResourceOwner == AuxProcessResourceOwner ||
     254             :            CurrentResourceOwner == NULL);
     255         312 :     CurrentResourceOwner = AuxProcessResourceOwner;
     256             : 
     257         312 :     backup_started_in_recovery = RecoveryInProgress();
     258             : 
     259         312 :     InitializeBackupManifest(&manifest, opt->manifest,
     260             :                              opt->manifest_checksum_type);
     261             : 
     262         312 :     total_checksum_failures = 0;
     263             : 
     264             :     /* Allocate backup related variables. */
     265         312 :     backup_state = (BackupState *) palloc0(sizeof(BackupState));
     266         312 :     tablespace_map = makeStringInfo();
     267             : 
     268         312 :     basebackup_progress_wait_checkpoint();
     269         312 :     do_pg_backup_start(opt->label, opt->fastcheckpoint, &state.tablespaces,
     270             :                        backup_state, tablespace_map);
     271             : 
     272         312 :     state.startptr = backup_state->startpoint;
     273         312 :     state.starttli = backup_state->starttli;
     274             : 
     275             :     /*
     276             :      * Once do_pg_backup_start has been called, ensure that any failure causes
     277             :      * us to abort the backup so we don't "leak" a backup counter. For this
     278             :      * reason, *all* functionality between do_pg_backup_start() and the end of
     279             :      * do_pg_backup_stop() should be inside the error cleanup block!
     280             :      */
     281             : 
     282         312 :     PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
     283             :     {
     284             :         ListCell   *lc;
     285             :         tablespaceinfo *newti;
     286             : 
     287             :         /* If this is an incremental backup, execute preparatory steps. */
     288         312 :         if (ib != NULL)
     289          18 :             PrepareForIncrementalBackup(ib, backup_state);
     290             : 
     291             :         /* Add a node for the base directory at the end */
     292         312 :         newti = palloc0(sizeof(tablespaceinfo));
     293         312 :         newti->size = -1;
     294         312 :         state.tablespaces = lappend(state.tablespaces, newti);
     295             : 
     296             :         /*
     297             :          * Calculate the total backup size by summing up the size of each
     298             :          * tablespace
     299             :          */
     300         312 :         if (opt->progress)
     301             :         {
     302         310 :             basebackup_progress_estimate_backup_size();
     303             : 
     304         692 :             foreach(lc, state.tablespaces)
     305             :             {
     306         382 :                 tablespaceinfo *tmp = (tablespaceinfo *) lfirst(lc);
     307             : 
     308         382 :                 if (tmp->path == NULL)
     309         310 :                     tmp->size = sendDir(sink, ".", 1, true, state.tablespaces,
     310             :                                         true, NULL, InvalidOid, NULL);
     311             :                 else
     312          72 :                     tmp->size = sendTablespace(sink, tmp->path, tmp->oid, true,
     313             :                                                NULL, NULL);
     314         382 :                 state.bytes_total += tmp->size;
     315             :             }
     316         310 :             state.bytes_total_is_valid = true;
     317             :         }
     318             : 
     319             :         /* notify basebackup sink about start of backup */
     320         312 :         bbsink_begin_backup(sink, &state, SINK_BUFFER_LENGTH);
     321             : 
     322             :         /* Send off our tablespaces one by one */
     323         682 :         foreach(lc, state.tablespaces)
     324             :         {
     325         384 :             tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
     326             : 
     327         384 :             if (ti->path == NULL)
     328             :             {
     329             :                 struct stat statbuf;
     330         312 :                 bool        sendtblspclinks = true;
     331             :                 char       *backup_label;
     332             : 
     333         312 :                 bbsink_begin_archive(sink, "base.tar");
     334             : 
     335             :                 /* In the main tar, include the backup_label first... */
     336         312 :                 backup_label = build_backup_content(backup_state, false);
     337         312 :                 sendFileWithContent(sink, BACKUP_LABEL_FILE,
     338             :                                     backup_label, -1, &manifest);
     339         312 :                 pfree(backup_label);
     340             : 
     341             :                 /* Then the tablespace_map file, if required... */
     342         312 :                 if (opt->sendtblspcmapfile)
     343             :                 {
     344          50 :                     sendFileWithContent(sink, TABLESPACE_MAP,
     345          50 :                                         tablespace_map->data, -1, &manifest);
     346          50 :                     sendtblspclinks = false;
     347             :                 }
     348             : 
     349             :                 /* Then the bulk of the files... */
     350         312 :                 sendDir(sink, ".", 1, false, state.tablespaces,
     351             :                         sendtblspclinks, &manifest, InvalidOid, ib);
     352             : 
     353             :                 /* ... and pg_control after everything else. */
     354         298 :                 if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
     355           0 :                     ereport(ERROR,
     356             :                             (errcode_for_file_access(),
     357             :                              errmsg("could not stat file \"%s\": %m",
     358             :                                     XLOG_CONTROL_FILE)));
     359         298 :                 sendFile(sink, XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf,
     360             :                          false, InvalidOid, InvalidOid,
     361             :                          InvalidRelFileNumber, 0, &manifest, 0, NULL, 0);
     362             :             }
     363             :             else
     364             :             {
     365          72 :                 char       *archive_name = psprintf("%u.tar", ti->oid);
     366             : 
     367          72 :                 bbsink_begin_archive(sink, archive_name);
     368             : 
     369          72 :                 sendTablespace(sink, ti->path, ti->oid, false, &manifest, ib);
     370             :             }
     371             : 
     372             :             /*
     373             :              * If we're including WAL, and this is the main data directory we
     374             :              * don't treat this as the end of the tablespace. Instead, we will
     375             :              * include the xlog files below and stop afterwards. This is safe
     376             :              * since the main data directory is always sent *last*.
     377             :              */
     378         370 :             if (opt->includewal && ti->path == NULL)
     379             :             {
     380             :                 Assert(lnext(state.tablespaces, lc) == NULL);
     381             :             }
     382             :             else
     383             :             {
     384             :                 /* Properly terminate the tarfile. */
     385             :                 StaticAssertDecl(2 * TAR_BLOCK_SIZE <= BLCKSZ,
     386             :                                  "BLCKSZ too small for 2 tar blocks");
     387         344 :                 memset(sink->bbs_buffer, 0, 2 * TAR_BLOCK_SIZE);
     388         344 :                 bbsink_archive_contents(sink, 2 * TAR_BLOCK_SIZE);
     389             : 
     390             :                 /* OK, that's the end of the archive. */
     391         344 :                 bbsink_end_archive(sink);
     392             :             }
     393             :         }
     394             : 
     395         298 :         basebackup_progress_wait_wal_archive(&state);
     396         298 :         do_pg_backup_stop(backup_state, !opt->nowait);
     397             : 
     398         298 :         endptr = backup_state->stoppoint;
     399         298 :         endtli = backup_state->stoptli;
     400             : 
     401             :         /* Deallocate backup-related variables. */
     402         298 :         destroyStringInfo(tablespace_map);
     403         298 :         pfree(backup_state);
     404             :     }
     405         302 :     PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
     406             : 
     407             : 
     408         298 :     if (opt->includewal)
     409             :     {
     410             :         /*
     411             :          * We've left the last tar file "open", so we can now append the
     412             :          * required WAL files to it.
     413             :          */
     414             :         char        pathbuf[MAXPGPATH];
     415             :         XLogSegNo   segno;
     416             :         XLogSegNo   startsegno;
     417             :         XLogSegNo   endsegno;
     418             :         struct stat statbuf;
     419          26 :         List       *historyFileList = NIL;
     420          26 :         List       *walFileList = NIL;
     421             :         char        firstoff[MAXFNAMELEN];
     422             :         char        lastoff[MAXFNAMELEN];
     423             :         DIR        *dir;
     424             :         struct dirent *de;
     425             :         ListCell   *lc;
     426             :         TimeLineID  tli;
     427             : 
     428          26 :         basebackup_progress_transfer_wal();
     429             : 
     430             :         /*
     431             :          * I'd rather not worry about timelines here, so scan pg_wal and
     432             :          * include all WAL files in the range between 'startptr' and 'endptr',
     433             :          * regardless of the timeline the file is stamped with. If there are
     434             :          * some spurious WAL files belonging to timelines that don't belong in
     435             :          * this server's history, they will be included too. Normally there
     436             :          * shouldn't be such files, but if there are, there's little harm in
     437             :          * including them.
     438             :          */
     439          26 :         XLByteToSeg(state.startptr, startsegno, wal_segment_size);
     440          26 :         XLogFileName(firstoff, state.starttli, startsegno, wal_segment_size);
     441          26 :         XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
     442          26 :         XLogFileName(lastoff, endtli, endsegno, wal_segment_size);
     443             : 
     444          26 :         dir = AllocateDir("pg_wal");
     445         188 :         while ((de = ReadDir(dir, "pg_wal")) != NULL)
     446             :         {
     447             :             /* Does it look like a WAL segment, and is it in the range? */
     448         162 :             if (IsXLogFileName(de->d_name) &&
     449          58 :                 strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
     450          58 :                 strcmp(de->d_name + 8, lastoff + 8) <= 0)
     451             :             {
     452          26 :                 walFileList = lappend(walFileList, pstrdup(de->d_name));
     453             :             }
     454             :             /* Does it look like a timeline history file? */
     455         136 :             else if (IsTLHistoryFileName(de->d_name))
     456             :             {
     457           0 :                 historyFileList = lappend(historyFileList, pstrdup(de->d_name));
     458             :             }
     459             :         }
     460          26 :         FreeDir(dir);
     461             : 
     462             :         /*
     463             :          * Before we go any further, check that none of the WAL segments we
     464             :          * need were removed.
     465             :          */
     466          26 :         CheckXLogRemoved(startsegno, state.starttli);
     467             : 
     468             :         /*
     469             :          * Sort the WAL filenames.  We want to send the files in order from
     470             :          * oldest to newest, to reduce the chance that a file is recycled
     471             :          * before we get a chance to send it over.
     472             :          */
     473          26 :         list_sort(walFileList, compareWalFileNames);
     474             : 
     475             :         /*
     476             :          * There must be at least one xlog file in the pg_wal directory, since
     477             :          * we are doing backup-including-xlog.
     478             :          */
     479          26 :         if (walFileList == NIL)
     480           0 :             ereport(ERROR,
     481             :                     (errmsg("could not find any WAL files")));
     482             : 
     483             :         /*
     484             :          * Sanity check: the first and last segment should cover startptr and
     485             :          * endptr, with no gaps in between.
     486             :          */
     487          26 :         XLogFromFileName((char *) linitial(walFileList),
     488             :                          &tli, &segno, wal_segment_size);
     489          26 :         if (segno != startsegno)
     490             :         {
     491             :             char        startfname[MAXFNAMELEN];
     492             : 
     493           0 :             XLogFileName(startfname, state.starttli, startsegno,
     494             :                          wal_segment_size);
     495           0 :             ereport(ERROR,
     496             :                     (errmsg("could not find WAL file \"%s\"", startfname)));
     497             :         }
     498          52 :         foreach(lc, walFileList)
     499             :         {
     500          26 :             char       *walFileName = (char *) lfirst(lc);
     501          26 :             XLogSegNo   currsegno = segno;
     502          26 :             XLogSegNo   nextsegno = segno + 1;
     503             : 
     504          26 :             XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
     505          26 :             if (!(nextsegno == segno || currsegno == segno))
     506             :             {
     507             :                 char        nextfname[MAXFNAMELEN];
     508             : 
     509           0 :                 XLogFileName(nextfname, tli, nextsegno, wal_segment_size);
     510           0 :                 ereport(ERROR,
     511             :                         (errmsg("could not find WAL file \"%s\"", nextfname)));
     512             :             }
     513             :         }
     514          26 :         if (segno != endsegno)
     515             :         {
     516             :             char        endfname[MAXFNAMELEN];
     517             : 
     518           0 :             XLogFileName(endfname, endtli, endsegno, wal_segment_size);
     519           0 :             ereport(ERROR,
     520             :                     (errmsg("could not find WAL file \"%s\"", endfname)));
     521             :         }
     522             : 
     523             :         /* Ok, we have everything we need. Send the WAL files. */
     524          52 :         foreach(lc, walFileList)
     525             :         {
     526          26 :             char       *walFileName = (char *) lfirst(lc);
     527             :             int         fd;
     528             :             ssize_t     cnt;
     529          26 :             pgoff_t     len = 0;
     530             : 
     531          26 :             snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
     532          26 :             XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
     533             : 
     534          26 :             fd = OpenTransientFile(pathbuf, O_RDONLY | PG_BINARY);
     535          26 :             if (fd < 0)
     536             :             {
     537           0 :                 int         save_errno = errno;
     538             : 
     539             :                 /*
     540             :                  * Most likely reason for this is that the file was already
     541             :                  * removed by a checkpoint, so check for that to get a better
     542             :                  * error message.
     543             :                  */
     544           0 :                 CheckXLogRemoved(segno, tli);
     545             : 
     546           0 :                 errno = save_errno;
     547           0 :                 ereport(ERROR,
     548             :                         (errcode_for_file_access(),
     549             :                          errmsg("could not open file \"%s\": %m", pathbuf)));
     550             :             }
     551             : 
     552          26 :             if (fstat(fd, &statbuf) != 0)
     553           0 :                 ereport(ERROR,
     554             :                         (errcode_for_file_access(),
     555             :                          errmsg("could not stat file \"%s\": %m",
     556             :                                 pathbuf)));
     557          26 :             if (statbuf.st_size != wal_segment_size)
     558             :             {
     559           0 :                 CheckXLogRemoved(segno, tli);
     560           0 :                 ereport(ERROR,
     561             :                         (errcode_for_file_access(),
     562             :                          errmsg("unexpected WAL file size \"%s\"", walFileName)));
     563             :             }
     564             : 
     565             :             /* send the WAL file itself */
     566          26 :             _tarWriteHeader(sink, pathbuf, NULL, &statbuf, false);
     567             : 
     568       13338 :             while ((cnt = basebackup_read_file(fd, sink->bbs_buffer,
     569       13312 :                                                Min(sink->bbs_buffer_length,
     570             :                                                    wal_segment_size - len),
     571             :                                                len, pathbuf, true)) > 0)
     572             :             {
     573       13312 :                 CheckXLogRemoved(segno, tli);
     574       13312 :                 bbsink_archive_contents(sink, cnt);
     575             : 
     576       13312 :                 len += cnt;
     577             : 
     578       13312 :                 if (len == wal_segment_size)
     579          26 :                     break;
     580             :             }
     581             : 
     582          26 :             if (len != wal_segment_size)
     583             :             {
     584           0 :                 CheckXLogRemoved(segno, tli);
     585           0 :                 ereport(ERROR,
     586             :                         (errcode_for_file_access(),
     587             :                          errmsg("unexpected WAL file size \"%s\"", walFileName)));
     588             :             }
     589             : 
     590             :             /*
     591             :              * wal_segment_size is a multiple of TAR_BLOCK_SIZE, so no need
     592             :              * for padding.
     593             :              */
     594             :             Assert(wal_segment_size % TAR_BLOCK_SIZE == 0);
     595             : 
     596          26 :             CloseTransientFile(fd);
     597             : 
     598             :             /*
     599             :              * Mark file as archived, otherwise files can get archived again
     600             :              * after promotion of a new node. This is in line with
     601             :              * walreceiver.c always doing an XLogArchiveForceDone() after a
     602             :              * complete segment.
     603             :              */
     604          26 :             StatusFilePath(pathbuf, walFileName, ".done");
     605          26 :             sendFileWithContent(sink, pathbuf, "", -1, &manifest);
     606             :         }
     607             : 
     608             :         /*
     609             :          * Send timeline history files too. Only the latest timeline history
     610             :          * file is required for recovery, and even that only if there happens
     611             :          * to be a timeline switch in the first WAL segment that contains the
     612             :          * checkpoint record, or if we're taking a base backup from a standby
     613             :          * server and the target timeline changes while the backup is taken.
     614             :          * But they are small and highly useful for debugging purposes, so
     615             :          * better include them all, always.
     616             :          */
     617          26 :         foreach(lc, historyFileList)
     618             :         {
     619           0 :             char       *fname = lfirst(lc);
     620             : 
     621           0 :             snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
     622             : 
     623           0 :             if (lstat(pathbuf, &statbuf) != 0)
     624           0 :                 ereport(ERROR,
     625             :                         (errcode_for_file_access(),
     626             :                          errmsg("could not stat file \"%s\": %m", pathbuf)));
     627             : 
     628           0 :             sendFile(sink, pathbuf, pathbuf, &statbuf, false,
     629             :                      InvalidOid, InvalidOid, InvalidRelFileNumber, 0,
     630             :                      &manifest, 0, NULL, 0);
     631             : 
     632             :             /* unconditionally mark file as archived */
     633           0 :             StatusFilePath(pathbuf, fname, ".done");
     634           0 :             sendFileWithContent(sink, pathbuf, "", -1, &manifest);
     635             :         }
     636             : 
     637             :         /* Properly terminate the tar file. */
     638             :         StaticAssertStmt(2 * TAR_BLOCK_SIZE <= BLCKSZ,
     639             :                          "BLCKSZ too small for 2 tar blocks");
     640          26 :         memset(sink->bbs_buffer, 0, 2 * TAR_BLOCK_SIZE);
     641          26 :         bbsink_archive_contents(sink, 2 * TAR_BLOCK_SIZE);
     642             : 
     643             :         /* OK, that's the end of the archive. */
     644          26 :         bbsink_end_archive(sink);
     645             :     }
     646             : 
     647         298 :     AddWALInfoToBackupManifest(&manifest, state.startptr, state.starttli,
     648             :                                endptr, endtli);
     649             : 
     650         298 :     SendBackupManifest(&manifest, sink);
     651             : 
     652         298 :     bbsink_end_backup(sink, endptr, endtli);
     653             : 
     654         298 :     if (total_checksum_failures)
     655             :     {
     656           6 :         if (total_checksum_failures > 1)
     657           4 :             ereport(WARNING,
     658             :                     (errmsg_plural("%lld total checksum verification failure",
     659             :                                    "%lld total checksum verification failures",
     660             :                                    total_checksum_failures,
     661             :                                    total_checksum_failures)));
     662             : 
     663           6 :         ereport(ERROR,
     664             :                 (errcode(ERRCODE_DATA_CORRUPTED),
     665             :                  errmsg("checksum verification failure during base backup")));
     666             :     }
     667             : 
     668             :     /*
     669             :      * Make sure to free the manifest before the resource owners as manifests
     670             :      * use cryptohash contexts that may depend on resource owners (like
     671             :      * OpenSSL).
     672             :      */
     673         292 :     FreeBackupManifest(&manifest);
     674             : 
     675             :     /* clean up the resource owner we created */
     676         292 :     ReleaseAuxProcessResources(true);
     677             : 
     678         292 :     basebackup_progress_done();
     679         292 : }
     680             : 
     681             : /*
     682             :  * list_sort comparison function, to compare log/seg portion of WAL segment
     683             :  * filenames, ignoring the timeline portion.
     684             :  */
     685             : static int
     686           0 : compareWalFileNames(const ListCell *a, const ListCell *b)
     687             : {
     688           0 :     char       *fna = (char *) lfirst(a);
     689           0 :     char       *fnb = (char *) lfirst(b);
     690             : 
     691           0 :     return strcmp(fna + 8, fnb + 8);
     692             : }
     693             : 
     694             : /*
     695             :  * Parse the base backup options passed down by the parser
     696             :  */
     697             : static void
     698         346 : parse_basebackup_options(List *options, basebackup_options *opt)
     699             : {
     700             :     ListCell   *lopt;
     701         346 :     bool        o_label = false;
     702         346 :     bool        o_progress = false;
     703         346 :     bool        o_checkpoint = false;
     704         346 :     bool        o_nowait = false;
     705         346 :     bool        o_wal = false;
     706         346 :     bool        o_incremental = false;
     707         346 :     bool        o_maxrate = false;
     708         346 :     bool        o_tablespace_map = false;
     709         346 :     bool        o_noverify_checksums = false;
     710         346 :     bool        o_manifest = false;
     711         346 :     bool        o_manifest_checksums = false;
     712         346 :     bool        o_target = false;
     713         346 :     bool        o_target_detail = false;
     714         346 :     char       *target_str = NULL;
     715         346 :     char       *target_detail_str = NULL;
     716         346 :     bool        o_compression = false;
     717         346 :     bool        o_compression_detail = false;
     718         346 :     char       *compression_detail_str = NULL;
     719             : 
     720        3806 :     MemSet(opt, 0, sizeof(*opt));
     721         346 :     opt->manifest = MANIFEST_OPTION_NO;
     722         346 :     opt->manifest_checksum_type = CHECKSUM_TYPE_CRC32C;
     723         346 :     opt->compression = PG_COMPRESSION_NONE;
     724         346 :     opt->compression_specification.algorithm = PG_COMPRESSION_NONE;
     725             : 
     726        2600 :     foreach(lopt, options)
     727             :     {
     728        2260 :         DefElem    *defel = (DefElem *) lfirst(lopt);
     729             : 
     730        2260 :         if (strcmp(defel->defname, "label") == 0)
     731             :         {
     732         344 :             if (o_label)
     733           0 :                 ereport(ERROR,
     734             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     735             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     736         344 :             opt->label = defGetString(defel);
     737         344 :             o_label = true;
     738             :         }
     739        1916 :         else if (strcmp(defel->defname, "progress") == 0)
     740             :         {
     741         344 :             if (o_progress)
     742           0 :                 ereport(ERROR,
     743             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     744             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     745         344 :             opt->progress = defGetBoolean(defel);
     746         344 :             o_progress = true;
     747             :         }
     748        1572 :         else if (strcmp(defel->defname, "checkpoint") == 0)
     749             :         {
     750         326 :             char       *optval = defGetString(defel);
     751             : 
     752         326 :             if (o_checkpoint)
     753           0 :                 ereport(ERROR,
     754             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     755             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     756         326 :             if (pg_strcasecmp(optval, "fast") == 0)
     757         326 :                 opt->fastcheckpoint = true;
     758           0 :             else if (pg_strcasecmp(optval, "spread") == 0)
     759           0 :                 opt->fastcheckpoint = false;
     760             :             else
     761           0 :                 ereport(ERROR,
     762             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     763             :                          errmsg("unrecognized checkpoint type: \"%s\"",
     764             :                                 optval)));
     765         326 :             o_checkpoint = true;
     766             :         }
     767        1246 :         else if (strcmp(defel->defname, "wait") == 0)
     768             :         {
     769         330 :             if (o_nowait)
     770           0 :                 ereport(ERROR,
     771             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     772             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     773         330 :             opt->nowait = !defGetBoolean(defel);
     774         330 :             o_nowait = true;
     775             :         }
     776         916 :         else if (strcmp(defel->defname, "wal") == 0)
     777             :         {
     778          34 :             if (o_wal)
     779           0 :                 ereport(ERROR,
     780             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     781             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     782          34 :             opt->includewal = defGetBoolean(defel);
     783          34 :             o_wal = true;
     784             :         }
     785         882 :         else if (strcmp(defel->defname, "incremental") == 0)
     786             :         {
     787          18 :             if (o_incremental)
     788           0 :                 ereport(ERROR,
     789             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     790             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     791          18 :             opt->incremental = defGetBoolean(defel);
     792          18 :             if (opt->incremental && !summarize_wal)
     793           0 :                 ereport(ERROR,
     794             :                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     795             :                          errmsg("incremental backups cannot be taken unless WAL summarization is enabled")));
     796          18 :             o_incremental = true;
     797             :         }
     798         864 :         else if (strcmp(defel->defname, "max_rate") == 0)
     799             :         {
     800             :             int64       maxrate;
     801             : 
     802           4 :             if (o_maxrate)
     803           0 :                 ereport(ERROR,
     804             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     805             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     806             : 
     807           4 :             maxrate = defGetInt64(defel);
     808           4 :             if (maxrate < MAX_RATE_LOWER || maxrate > MAX_RATE_UPPER)
     809           0 :                 ereport(ERROR,
     810             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     811             :                          errmsg("%d is outside the valid range for parameter \"%s\" (%d .. %d)",
     812             :                                 (int) maxrate, "MAX_RATE", MAX_RATE_LOWER, MAX_RATE_UPPER)));
     813             : 
     814           4 :             opt->maxrate = (uint32) maxrate;
     815           4 :             o_maxrate = true;
     816             :         }
     817         860 :         else if (strcmp(defel->defname, "tablespace_map") == 0)
     818             :         {
     819          62 :             if (o_tablespace_map)
     820           0 :                 ereport(ERROR,
     821             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     822             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     823          62 :             opt->sendtblspcmapfile = defGetBoolean(defel);
     824          62 :             o_tablespace_map = true;
     825             :         }
     826         798 :         else if (strcmp(defel->defname, "verify_checksums") == 0)
     827             :         {
     828           2 :             if (o_noverify_checksums)
     829           0 :                 ereport(ERROR,
     830             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     831             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     832           2 :             noverify_checksums = !defGetBoolean(defel);
     833           2 :             o_noverify_checksums = true;
     834             :         }
     835         796 :         else if (strcmp(defel->defname, "manifest") == 0)
     836             :         {
     837         342 :             char       *optval = defGetString(defel);
     838             :             bool        manifest_bool;
     839             : 
     840         342 :             if (o_manifest)
     841           0 :                 ereport(ERROR,
     842             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     843             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     844         342 :             if (parse_bool(optval, &manifest_bool))
     845             :             {
     846         340 :                 if (manifest_bool)
     847         340 :                     opt->manifest = MANIFEST_OPTION_YES;
     848             :                 else
     849           0 :                     opt->manifest = MANIFEST_OPTION_NO;
     850             :             }
     851           2 :             else if (pg_strcasecmp(optval, "force-encode") == 0)
     852           2 :                 opt->manifest = MANIFEST_OPTION_FORCE_ENCODE;
     853             :             else
     854           0 :                 ereport(ERROR,
     855             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     856             :                          errmsg("unrecognized manifest option: \"%s\"",
     857             :                                 optval)));
     858         342 :             o_manifest = true;
     859             :         }
     860         454 :         else if (strcmp(defel->defname, "manifest_checksums") == 0)
     861             :         {
     862          28 :             char       *optval = defGetString(defel);
     863             : 
     864          28 :             if (o_manifest_checksums)
     865           0 :                 ereport(ERROR,
     866             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     867             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     868          28 :             if (!pg_checksum_parse_type(optval,
     869             :                                         &opt->manifest_checksum_type))
     870           4 :                 ereport(ERROR,
     871             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     872             :                          errmsg("unrecognized checksum algorithm: \"%s\"",
     873             :                                 optval)));
     874          24 :             o_manifest_checksums = true;
     875             :         }
     876         426 :         else if (strcmp(defel->defname, "target") == 0)
     877             :         {
     878         340 :             if (o_target)
     879           0 :                 ereport(ERROR,
     880             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     881             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     882         340 :             target_str = defGetString(defel);
     883         340 :             o_target = true;
     884             :         }
     885          86 :         else if (strcmp(defel->defname, "target_detail") == 0)
     886             :         {
     887          14 :             char       *optval = defGetString(defel);
     888             : 
     889          14 :             if (o_target_detail)
     890           0 :                 ereport(ERROR,
     891             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     892             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     893          14 :             target_detail_str = optval;
     894          14 :             o_target_detail = true;
     895             :         }
     896          72 :         else if (strcmp(defel->defname, "compression") == 0)
     897             :         {
     898          50 :             char       *optval = defGetString(defel);
     899             : 
     900          50 :             if (o_compression)
     901           0 :                 ereport(ERROR,
     902             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     903             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     904          50 :             if (!parse_compress_algorithm(optval, &opt->compression))
     905           2 :                 ereport(ERROR,
     906             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     907             :                          errmsg("unrecognized compression algorithm: \"%s\"",
     908             :                                 optval)));
     909          48 :             o_compression = true;
     910             :         }
     911          22 :         else if (strcmp(defel->defname, "compression_detail") == 0)
     912             :         {
     913          22 :             if (o_compression_detail)
     914           0 :                 ereport(ERROR,
     915             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     916             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     917          22 :             compression_detail_str = defGetString(defel);
     918          22 :             o_compression_detail = true;
     919             :         }
     920             :         else
     921           0 :             ereport(ERROR,
     922             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     923             :                      errmsg("unrecognized base backup option: \"%s\"",
     924             :                             defel->defname)));
     925             :     }
     926             : 
     927         340 :     if (opt->label == NULL)
     928           2 :         opt->label = "base backup";
     929         340 :     if (opt->manifest == MANIFEST_OPTION_NO)
     930             :     {
     931           4 :         if (o_manifest_checksums)
     932           0 :             ereport(ERROR,
     933             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     934             :                      errmsg("manifest checksums require a backup manifest")));
     935           4 :         opt->manifest_checksum_type = CHECKSUM_TYPE_NONE;
     936             :     }
     937             : 
     938         340 :     if (target_str == NULL)
     939             :     {
     940           2 :         if (target_detail_str != NULL)
     941           0 :             ereport(ERROR,
     942             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     943             :                      errmsg("target detail cannot be used without target")));
     944           2 :         opt->use_copytblspc = true;
     945           2 :         opt->send_to_client = true;
     946             :     }
     947         338 :     else if (strcmp(target_str, "client") == 0)
     948             :     {
     949         312 :         if (target_detail_str != NULL)
     950           0 :             ereport(ERROR,
     951             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     952             :                      errmsg("target \"%s\" does not accept a target detail",
     953             :                             target_str)));
     954         312 :         opt->send_to_client = true;
     955             :     }
     956             :     else
     957          22 :         opt->target_handle =
     958          26 :             BaseBackupGetTargetHandle(target_str, target_detail_str);
     959             : 
     960         336 :     if (o_compression_detail && !o_compression)
     961           0 :         ereport(ERROR,
     962             :                 (errcode(ERRCODE_SYNTAX_ERROR),
     963             :                  errmsg("compression detail cannot be specified unless compression is enabled")));
     964             : 
     965         336 :     if (o_compression)
     966             :     {
     967             :         char       *error_detail;
     968             : 
     969          44 :         parse_compress_specification(opt->compression, compression_detail_str,
     970             :                                      &opt->compression_specification);
     971             :         error_detail =
     972          44 :             validate_compress_specification(&opt->compression_specification);
     973          44 :         if (error_detail != NULL)
     974          18 :             ereport(ERROR,
     975             :                     errcode(ERRCODE_SYNTAX_ERROR),
     976             :                     errmsg("invalid compression specification: %s",
     977             :                            error_detail));
     978             :     }
     979         318 : }
     980             : 
     981             : 
     982             : /*
     983             :  * SendBaseBackup() - send a complete base backup.
     984             :  *
     985             :  * The function will put the system into backup mode like pg_backup_start()
     986             :  * does, so that the backup is consistent even though we read directly from
     987             :  * the filesystem, bypassing the buffer cache.
     988             :  */
     989             : void
     990         348 : SendBaseBackup(BaseBackupCmd *cmd, IncrementalBackupInfo *ib)
     991             : {
     992             :     basebackup_options opt;
     993             :     bbsink     *sink;
     994         348 :     SessionBackupState status = get_backup_status();
     995             : 
     996         348 :     if (status == SESSION_BACKUP_RUNNING)
     997           2 :         ereport(ERROR,
     998             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     999             :                  errmsg("a backup is already in progress in this session")));
    1000             : 
    1001         346 :     parse_basebackup_options(cmd->options, &opt);
    1002             : 
    1003         318 :     WalSndSetState(WALSNDSTATE_BACKUP);
    1004             : 
    1005         318 :     if (update_process_title)
    1006             :     {
    1007             :         char        activitymsg[50];
    1008             : 
    1009         318 :         snprintf(activitymsg, sizeof(activitymsg), "sending backup \"%s\"",
    1010             :                  opt.label);
    1011         318 :         set_ps_display(activitymsg);
    1012             :     }
    1013             : 
    1014             :     /*
    1015             :      * If we're asked to perform an incremental backup and the user has not
    1016             :      * supplied a manifest, that's an ERROR.
    1017             :      *
    1018             :      * If we're asked to perform a full backup and the user did supply a
    1019             :      * manifest, just ignore it.
    1020             :      */
    1021         318 :     if (!opt.incremental)
    1022         300 :         ib = NULL;
    1023          18 :     else if (ib == NULL)
    1024           0 :         ereport(ERROR,
    1025             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1026             :                  errmsg("must UPLOAD_MANIFEST before performing an incremental BASE_BACKUP")));
    1027             : 
    1028             :     /*
    1029             :      * If the target is specifically 'client' then set up to stream the backup
    1030             :      * to the client; otherwise, it's being sent someplace else and should not
    1031             :      * be sent to the client. BaseBackupGetSink has the job of setting up a
    1032             :      * sink to send the backup data wherever it needs to go.
    1033             :      */
    1034         318 :     sink = bbsink_copystream_new(opt.send_to_client);
    1035         318 :     if (opt.target_handle != NULL)
    1036          22 :         sink = BaseBackupGetSink(opt.target_handle, sink);
    1037             : 
    1038             :     /* Set up network throttling, if client requested it */
    1039         312 :     if (opt.maxrate > 0)
    1040           4 :         sink = bbsink_throttle_new(sink, opt.maxrate);
    1041             : 
    1042             :     /* Set up server-side compression, if client requested it */
    1043         312 :     if (opt.compression == PG_COMPRESSION_GZIP)
    1044           4 :         sink = bbsink_gzip_new(sink, &opt.compression_specification);
    1045         308 :     else if (opt.compression == PG_COMPRESSION_LZ4)
    1046           4 :         sink = bbsink_lz4_new(sink, &opt.compression_specification);
    1047         304 :     else if (opt.compression == PG_COMPRESSION_ZSTD)
    1048           0 :         sink = bbsink_zstd_new(sink, &opt.compression_specification);
    1049             : 
    1050             :     /* Set up progress reporting. */
    1051         312 :     sink = bbsink_progress_new(sink, opt.progress);
    1052             : 
    1053             :     /*
    1054             :      * Perform the base backup, but make sure we clean up the bbsink even if
    1055             :      * an error occurs.
    1056             :      */
    1057         312 :     PG_TRY();
    1058             :     {
    1059         312 :         perform_base_backup(&opt, sink, ib);
    1060             :     }
    1061          10 :     PG_FINALLY();
    1062             :     {
    1063         302 :         bbsink_cleanup(sink);
    1064             :     }
    1065         302 :     PG_END_TRY();
    1066         292 : }
    1067             : 
    1068             : /*
    1069             :  * Inject a file with given name and content in the output tar stream.
    1070             :  *
    1071             :  * "len" can optionally be set to an arbitrary length of data sent.  If set
    1072             :  * to -1, the content sent is treated as a string with strlen() as length.
    1073             :  */
    1074             : static void
    1075         388 : sendFileWithContent(bbsink *sink, const char *filename, const char *content,
    1076             :                     int len, backup_manifest_info *manifest)
    1077             : {
    1078             :     struct stat statbuf;
    1079         388 :     int         bytes_done = 0;
    1080             :     pg_checksum_context checksum_ctx;
    1081             : 
    1082         388 :     if (pg_checksum_init(&checksum_ctx, manifest->checksum_type) < 0)
    1083           0 :         elog(ERROR, "could not initialize checksum of file \"%s\"",
    1084             :              filename);
    1085             : 
    1086         388 :     if (len < 0)
    1087         388 :         len = strlen(content);
    1088             : 
    1089             :     /*
    1090             :      * Construct a stat struct for the file we're injecting in the tar.
    1091             :      */
    1092             : 
    1093             :     /* Windows doesn't have the concept of uid and gid */
    1094             : #ifdef WIN32
    1095             :     statbuf.st_uid = 0;
    1096             :     statbuf.st_gid = 0;
    1097             : #else
    1098         388 :     statbuf.st_uid = geteuid();
    1099         388 :     statbuf.st_gid = getegid();
    1100             : #endif
    1101         388 :     statbuf.st_mtime = time(NULL);
    1102         388 :     statbuf.st_mode = pg_file_create_mode;
    1103         388 :     statbuf.st_size = len;
    1104             : 
    1105         388 :     _tarWriteHeader(sink, filename, NULL, &statbuf, false);
    1106             : 
    1107         388 :     if (pg_checksum_update(&checksum_ctx, (uint8 *) content, len) < 0)
    1108           0 :         elog(ERROR, "could not update checksum of file \"%s\"",
    1109             :              filename);
    1110             : 
    1111         710 :     while (bytes_done < len)
    1112             :     {
    1113         322 :         size_t      remaining = len - bytes_done;
    1114         322 :         size_t      nbytes = Min(sink->bbs_buffer_length, remaining);
    1115             : 
    1116         322 :         memcpy(sink->bbs_buffer, content, nbytes);
    1117         322 :         bbsink_archive_contents(sink, nbytes);
    1118         322 :         bytes_done += nbytes;
    1119         322 :         content += nbytes;
    1120             :     }
    1121             : 
    1122         388 :     _tarWritePadding(sink, len);
    1123             : 
    1124         388 :     AddFileToBackupManifest(manifest, InvalidOid, filename, len,
    1125         388 :                             (pg_time_t) statbuf.st_mtime, &checksum_ctx);
    1126         388 : }
    1127             : 
    1128             : /*
    1129             :  * Include the tablespace directory pointed to by 'path' in the output tar
    1130             :  * stream.  If 'sizeonly' is true, we just calculate a total length and return
    1131             :  * it, without actually sending anything.
    1132             :  *
    1133             :  * Only used to send auxiliary tablespaces, not PGDATA.
    1134             :  */
    1135             : static int64
    1136         144 : sendTablespace(bbsink *sink, char *path, Oid spcoid, bool sizeonly,
    1137             :                backup_manifest_info *manifest, IncrementalBackupInfo *ib)
    1138             : {
    1139             :     int64       size;
    1140             :     char        pathbuf[MAXPGPATH];
    1141             :     struct stat statbuf;
    1142             : 
    1143             :     /*
    1144             :      * 'path' points to the tablespace location, but we only want to include
    1145             :      * the version directory in it that belongs to us.
    1146             :      */
    1147         144 :     snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path,
    1148             :              TABLESPACE_VERSION_DIRECTORY);
    1149             : 
    1150             :     /*
    1151             :      * Store a directory entry in the tar file so we get the permissions
    1152             :      * right.
    1153             :      */
    1154         144 :     if (lstat(pathbuf, &statbuf) != 0)
    1155             :     {
    1156           0 :         if (errno != ENOENT)
    1157           0 :             ereport(ERROR,
    1158             :                     (errcode_for_file_access(),
    1159             :                      errmsg("could not stat file or directory \"%s\": %m",
    1160             :                             pathbuf)));
    1161             : 
    1162             :         /* If the tablespace went away while scanning, it's no error. */
    1163           0 :         return 0;
    1164             :     }
    1165             : 
    1166         144 :     size = _tarWriteHeader(sink, TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
    1167             :                            sizeonly);
    1168             : 
    1169             :     /* Send all the files in the tablespace version directory */
    1170         144 :     size += sendDir(sink, pathbuf, strlen(path), sizeonly, NIL, true, manifest,
    1171             :                     spcoid, ib);
    1172             : 
    1173         144 :     return size;
    1174             : }
    1175             : 
    1176             : /*
    1177             :  * Include all files from the given directory in the output tar stream. If
    1178             :  * 'sizeonly' is true, we just calculate a total length and return it, without
    1179             :  * actually sending anything.
    1180             :  *
    1181             :  * Omit any directory in the tablespaces list, to avoid backing up
    1182             :  * tablespaces twice when they were created inside PGDATA.
    1183             :  *
    1184             :  * If sendtblspclinks is true, we need to include symlink
    1185             :  * information in the tar file. If not, we can skip that
    1186             :  * as it will be sent separately in the tablespace_map file.
    1187             :  */
    1188             : static int64
    1189       10740 : sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
    1190             :         List *tablespaces, bool sendtblspclinks, backup_manifest_info *manifest,
    1191             :         Oid spcoid, IncrementalBackupInfo *ib)
    1192             : {
    1193             :     DIR        *dir;
    1194             :     struct dirent *de;
    1195             :     char        pathbuf[MAXPGPATH * 2];
    1196             :     struct stat statbuf;
    1197       10740 :     int64       size = 0;
    1198             :     const char *lastDir;        /* Split last dir from parent path. */
    1199       10740 :     bool        isRelationDir = false;  /* Does directory contain relations? */
    1200       10740 :     bool        isGlobalDir = false;
    1201       10740 :     Oid         dboid = InvalidOid;
    1202       10740 :     BlockNumber *relative_block_numbers = NULL;
    1203             : 
    1204             :     /*
    1205             :      * Since this array is relatively large, avoid putting it on the stack.
    1206             :      * But we don't need it at all if this is not an incremental backup.
    1207             :      */
    1208       10740 :     if (ib != NULL)
    1209         314 :         relative_block_numbers = palloc(sizeof(BlockNumber) * RELSEG_SIZE);
    1210             : 
    1211             :     /*
    1212             :      * Determine if the current path is a database directory that can contain
    1213             :      * relations.
    1214             :      *
    1215             :      * Start by finding the location of the delimiter between the parent path
    1216             :      * and the current path.
    1217             :      */
    1218       10740 :     lastDir = last_dir_separator(path);
    1219             : 
    1220             :     /* Does this path look like a database path (i.e. all digits)? */
    1221       10740 :     if (lastDir != NULL &&
    1222       10118 :         strspn(lastDir + 1, "0123456789") == strlen(lastDir + 1))
    1223        1988 :     {
    1224             :         /* Part of path that contains the parent directory. */
    1225        1988 :         int         parentPathLen = lastDir - path;
    1226             : 
    1227             :         /*
    1228             :          * Mark path as a database directory if the parent path is either
    1229             :          * $PGDATA/base or a tablespace version path.
    1230             :          */
    1231        1988 :         if (strncmp(path, "./base", parentPathLen) == 0 ||
    1232         100 :             (parentPathLen >= (sizeof(TABLESPACE_VERSION_DIRECTORY) - 1) &&
    1233         100 :              strncmp(lastDir - (sizeof(TABLESPACE_VERSION_DIRECTORY) - 1),
    1234             :                      TABLESPACE_VERSION_DIRECTORY,
    1235             :                      sizeof(TABLESPACE_VERSION_DIRECTORY) - 1) == 0))
    1236             :         {
    1237        1988 :             isRelationDir = true;
    1238        1988 :             dboid = atooid(lastDir + 1);
    1239             :         }
    1240             :     }
    1241        8752 :     else if (strcmp(path, "./global") == 0)
    1242             :     {
    1243         614 :         isRelationDir = true;
    1244         614 :         isGlobalDir = true;
    1245             :     }
    1246             : 
    1247       10740 :     dir = AllocateDir(path);
    1248      660900 :     while ((de = ReadDir(dir, path)) != NULL)
    1249             :     {
    1250             :         int         excludeIdx;
    1251             :         bool        excludeFound;
    1252      650186 :         RelFileNumber relfilenumber = InvalidRelFileNumber;
    1253      650186 :         ForkNumber  relForkNum = InvalidForkNumber;
    1254      650186 :         unsigned    segno = 0;
    1255      650186 :         bool        isRelationFile = false;
    1256             : 
    1257             :         /* Skip special stuff */
    1258      650186 :         if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
    1259       30370 :             continue;
    1260             : 
    1261             :         /* Skip temporary files */
    1262      628746 :         if (strncmp(de->d_name,
    1263             :                     PG_TEMP_FILE_PREFIX,
    1264             :                     strlen(PG_TEMP_FILE_PREFIX)) == 0)
    1265         608 :             continue;
    1266             : 
    1267             :         /* Skip macOS system files */
    1268      628138 :         if (strcmp(de->d_name, ".DS_Store") == 0)
    1269         142 :             continue;
    1270             : 
    1271             :         /*
    1272             :          * Check if the postmaster has signaled us to exit, and abort with an
    1273             :          * error in that case. The error handler further up will call
    1274             :          * do_pg_abort_backup() for us. Also check that if the backup was
    1275             :          * started while still in recovery, the server wasn't promoted.
    1276             :          * do_pg_backup_stop() will check that too, but it's better to stop
    1277             :          * the backup early than continue to the end and fail there.
    1278             :          */
    1279      627996 :         CHECK_FOR_INTERRUPTS();
    1280      627986 :         if (RecoveryInProgress() != backup_started_in_recovery)
    1281           0 :             ereport(ERROR,
    1282             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1283             :                      errmsg("the standby was promoted during online backup"),
    1284             :                      errhint("This means that the backup being taken is corrupt "
    1285             :                              "and should not be used. "
    1286             :                              "Try taking another online backup.")));
    1287             : 
    1288             :         /* Scan for files that should be excluded */
    1289      627986 :         excludeFound = false;
    1290     5642438 :         for (excludeIdx = 0; excludeFiles[excludeIdx].name != NULL; excludeIdx++)
    1291             :         {
    1292     5016898 :             int         cmplen = strlen(excludeFiles[excludeIdx].name);
    1293             : 
    1294     5016898 :             if (!excludeFiles[excludeIdx].match_prefix)
    1295     4389184 :                 cmplen++;
    1296     5016898 :             if (strncmp(de->d_name, excludeFiles[excludeIdx].name, cmplen) == 0)
    1297             :             {
    1298        2446 :                 elog(DEBUG1, "file \"%s\" excluded from backup", de->d_name);
    1299        2446 :                 excludeFound = true;
    1300        2446 :                 break;
    1301             :             }
    1302             :         }
    1303             : 
    1304      627986 :         if (excludeFound)
    1305        2446 :             continue;
    1306             : 
    1307             :         /*
    1308             :          * If there could be non-temporary relation files in this directory,
    1309             :          * try to parse the filename.
    1310             :          */
    1311      625540 :         if (isRelationDir)
    1312             :             isRelationFile =
    1313      604672 :                 parse_filename_for_nontemp_relation(de->d_name,
    1314             :                                                     &relfilenumber,
    1315             :                                                     &relForkNum, &segno);
    1316             : 
    1317             :         /* Exclude all forks for unlogged tables except the init fork */
    1318      625540 :         if (isRelationFile && relForkNum != INIT_FORKNUM)
    1319             :         {
    1320             :             char        initForkFile[MAXPGPATH];
    1321             : 
    1322             :             /*
    1323             :              * If any other type of fork, check if there is an init fork with
    1324             :              * the same RelFileNumber. If so, the file can be excluded.
    1325             :              */
    1326      599460 :             snprintf(initForkFile, sizeof(initForkFile), "%s/%u_init",
    1327             :                      path, relfilenumber);
    1328             : 
    1329      599460 :             if (lstat(initForkFile, &statbuf) == 0)
    1330             :             {
    1331         140 :                 elog(DEBUG2,
    1332             :                      "unlogged relation file \"%s\" excluded from backup",
    1333             :                      de->d_name);
    1334             : 
    1335         140 :                 continue;
    1336             :             }
    1337             :         }
    1338             : 
    1339             :         /* Exclude temporary relations */
    1340      625400 :         if (OidIsValid(dboid) && looks_like_temp_rel_name(de->d_name))
    1341             :         {
    1342          72 :             elog(DEBUG2,
    1343             :                  "temporary relation file \"%s\" excluded from backup",
    1344             :                  de->d_name);
    1345             : 
    1346          72 :             continue;
    1347             :         }
    1348             : 
    1349      625328 :         snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path, de->d_name);
    1350             : 
    1351             :         /* Skip pg_control here to back up it last */
    1352      625328 :         if (strcmp(pathbuf, "./global/pg_control") == 0)
    1353         612 :             continue;
    1354             : 
    1355      624716 :         if (lstat(pathbuf, &statbuf) != 0)
    1356             :         {
    1357           0 :             if (errno != ENOENT)
    1358           0 :                 ereport(ERROR,
    1359             :                         (errcode_for_file_access(),
    1360             :                          errmsg("could not stat file or directory \"%s\": %m",
    1361             :                                 pathbuf)));
    1362             : 
    1363             :             /* If the file went away while scanning, it's not an error. */
    1364           0 :             continue;
    1365             :         }
    1366             : 
    1367             :         /* Scan for directories whose contents should be excluded */
    1368      624716 :         excludeFound = false;
    1369     4980502 :         for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++)
    1370             :         {
    1371     4360086 :             if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
    1372             :             {
    1373        4300 :                 elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
    1374        4300 :                 convert_link_to_directory(pathbuf, &statbuf);
    1375        4300 :                 size += _tarWriteHeader(sink, pathbuf + basepathlen + 1, NULL,
    1376             :                                         &statbuf, sizeonly);
    1377        4298 :                 excludeFound = true;
    1378        4298 :                 break;
    1379             :             }
    1380             :         }
    1381             : 
    1382      624714 :         if (excludeFound)
    1383        4298 :             continue;
    1384             : 
    1385             :         /*
    1386             :          * We can skip pg_wal, the WAL segments need to be fetched from the
    1387             :          * WAL archive anyway. But include it as an empty directory anyway, so
    1388             :          * we get permissions right.
    1389             :          */
    1390      620416 :         if (strcmp(pathbuf, "./pg_wal") == 0)
    1391             :         {
    1392             :             /* If pg_wal is a symlink, write it as a directory anyway */
    1393         612 :             convert_link_to_directory(pathbuf, &statbuf);
    1394         612 :             size += _tarWriteHeader(sink, pathbuf + basepathlen + 1, NULL,
    1395             :                                     &statbuf, sizeonly);
    1396             : 
    1397             :             /*
    1398             :              * Also send archive_status and summaries directories (by
    1399             :              * hackishly reusing statbuf from above ...).
    1400             :              */
    1401         612 :             size += _tarWriteHeader(sink, "./pg_wal/archive_status", NULL,
    1402             :                                     &statbuf, sizeonly);
    1403         612 :             size += _tarWriteHeader(sink, "./pg_wal/summaries", NULL,
    1404             :                                     &statbuf, sizeonly);
    1405             : 
    1406         612 :             continue;           /* don't recurse into pg_wal */
    1407             :         }
    1408             : 
    1409             :         /* Allow symbolic links in pg_tblspc only */
    1410      619804 :         if (strcmp(path, "./pg_tblspc") == 0 && S_ISLNK(statbuf.st_mode))
    1411          76 :         {
    1412             :             char        linkpath[MAXPGPATH];
    1413             :             int         rllen;
    1414             : 
    1415          76 :             rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
    1416          76 :             if (rllen < 0)
    1417           0 :                 ereport(ERROR,
    1418             :                         (errcode_for_file_access(),
    1419             :                          errmsg("could not read symbolic link \"%s\": %m",
    1420             :                                 pathbuf)));
    1421          76 :             if (rllen >= sizeof(linkpath))
    1422           0 :                 ereport(ERROR,
    1423             :                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1424             :                          errmsg("symbolic link \"%s\" target is too long",
    1425             :                                 pathbuf)));
    1426          76 :             linkpath[rllen] = '\0';
    1427             : 
    1428          76 :             size += _tarWriteHeader(sink, pathbuf + basepathlen + 1, linkpath,
    1429             :                                     &statbuf, sizeonly);
    1430             :         }
    1431      619728 :         else if (S_ISDIR(statbuf.st_mode))
    1432             :         {
    1433       10078 :             bool        skip_this_dir = false;
    1434             :             ListCell   *lc;
    1435             : 
    1436             :             /*
    1437             :              * Store a directory entry in the tar file so we can get the
    1438             :              * permissions right.
    1439             :              */
    1440       10078 :             size += _tarWriteHeader(sink, pathbuf + basepathlen + 1, NULL, &statbuf,
    1441             :                                     sizeonly);
    1442             : 
    1443             :             /*
    1444             :              * Call ourselves recursively for a directory, unless it happens
    1445             :              * to be a separate tablespace located within PGDATA.
    1446             :              */
    1447       22370 :             foreach(lc, tablespaces)
    1448             :             {
    1449       12348 :                 tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
    1450             : 
    1451             :                 /*
    1452             :                  * ti->rpath is the tablespace relative path within PGDATA, or
    1453             :                  * NULL if the tablespace has been properly located somewhere
    1454             :                  * else.
    1455             :                  *
    1456             :                  * Skip past the leading "./" in pathbuf when comparing.
    1457             :                  */
    1458       12348 :                 if (ti->rpath && strcmp(ti->rpath, pathbuf + 2) == 0)
    1459             :                 {
    1460          56 :                     skip_this_dir = true;
    1461          56 :                     break;
    1462             :                 }
    1463             :             }
    1464             : 
    1465             :             /*
    1466             :              * skip sending directories inside pg_tblspc, if not required.
    1467             :              */
    1468       10078 :             if (strcmp(pathbuf, "./pg_tblspc") == 0 && !sendtblspclinks)
    1469          48 :                 skip_this_dir = true;
    1470             : 
    1471       10078 :             if (!skip_this_dir)
    1472        9974 :                 size += sendDir(sink, pathbuf, basepathlen, sizeonly, tablespaces,
    1473             :                                 sendtblspclinks, manifest, spcoid, ib);
    1474             :         }
    1475      609650 :         else if (S_ISREG(statbuf.st_mode))
    1476             :         {
    1477      609650 :             bool        sent = false;
    1478      609650 :             unsigned    num_blocks_required = 0;
    1479      609650 :             unsigned    truncation_block_length = 0;
    1480             :             char        tarfilenamebuf[MAXPGPATH * 2];
    1481      609650 :             char       *tarfilename = pathbuf + basepathlen + 1;
    1482      609650 :             FileBackupMethod method = BACK_UP_FILE_FULLY;
    1483             : 
    1484      609650 :             if (ib != NULL && isRelationFile)
    1485             :             {
    1486             :                 Oid         relspcoid;
    1487             :                 char       *lookup_path;
    1488             : 
    1489       18406 :                 if (OidIsValid(spcoid))
    1490             :                 {
    1491          18 :                     relspcoid = spcoid;
    1492          18 :                     lookup_path = psprintf("%s/%u/%s", PG_TBLSPC_DIR, spcoid,
    1493             :                                            tarfilename);
    1494             :                 }
    1495             :                 else
    1496             :                 {
    1497       18388 :                     if (isGlobalDir)
    1498        1044 :                         relspcoid = GLOBALTABLESPACE_OID;
    1499             :                     else
    1500       17344 :                         relspcoid = DEFAULTTABLESPACE_OID;
    1501       18388 :                     lookup_path = pstrdup(tarfilename);
    1502             :                 }
    1503             : 
    1504       18406 :                 method = GetFileBackupMethod(ib, lookup_path, dboid, relspcoid,
    1505             :                                              relfilenumber, relForkNum,
    1506       18406 :                                              segno, statbuf.st_size,
    1507             :                                              &num_blocks_required,
    1508             :                                              relative_block_numbers,
    1509             :                                              &truncation_block_length);
    1510       18406 :                 if (method == BACK_UP_FILE_INCREMENTALLY)
    1511             :                 {
    1512       12002 :                     statbuf.st_size =
    1513       12002 :                         GetIncrementalFileSize(num_blocks_required);
    1514       12002 :                     snprintf(tarfilenamebuf, sizeof(tarfilenamebuf),
    1515             :                              "%s/INCREMENTAL.%s",
    1516       12002 :                              path + basepathlen + 1,
    1517       12002 :                              de->d_name);
    1518       12002 :                     tarfilename = tarfilenamebuf;
    1519             :                 }
    1520             : 
    1521       18406 :                 pfree(lookup_path);
    1522             :             }
    1523             : 
    1524      609650 :             if (!sizeonly)
    1525      299342 :                 sent = sendFile(sink, pathbuf, tarfilename, &statbuf,
    1526             :                                 true, dboid, spcoid,
    1527             :                                 relfilenumber, segno, manifest,
    1528             :                                 num_blocks_required,
    1529             :                                 method == BACK_UP_FILE_INCREMENTALLY ? relative_block_numbers : NULL,
    1530             :                                 truncation_block_length);
    1531             : 
    1532      609648 :             if (sent || sizeonly)
    1533             :             {
    1534             :                 /* Add size. */
    1535      609648 :                 size += statbuf.st_size;
    1536             : 
    1537             :                 /* Pad to a multiple of the tar block size. */
    1538      609648 :                 size += tarPaddingBytesRequired(statbuf.st_size);
    1539             : 
    1540             :                 /* Size of the header for the file. */
    1541      609648 :                 size += TAR_BLOCK_SIZE;
    1542             :             }
    1543             :         }
    1544             :         else
    1545           0 :             ereport(WARNING,
    1546             :                     (errmsg("skipping special file \"%s\"", pathbuf)));
    1547             :     }
    1548             : 
    1549       10714 :     if (relative_block_numbers != NULL)
    1550         314 :         pfree(relative_block_numbers);
    1551             : 
    1552       10714 :     FreeDir(dir);
    1553       10714 :     return size;
    1554             : }
    1555             : 
    1556             : /*
    1557             :  * Given the member, write the TAR header & send the file.
    1558             :  *
    1559             :  * If 'missing_ok' is true, will not throw an error if the file is not found.
    1560             :  *
    1561             :  * If dboid is anything other than InvalidOid then any checksum failures
    1562             :  * detected will get reported to the cumulative stats system.
    1563             :  *
    1564             :  * If the file is to be sent incrementally, then num_incremental_blocks
    1565             :  * should be the number of blocks to be sent, and incremental_blocks
    1566             :  * an array of block numbers relative to the start of the current segment.
    1567             :  * If the whole file is to be sent, then incremental_blocks should be NULL,
    1568             :  * and num_incremental_blocks can have any value, as it will be ignored.
    1569             :  *
    1570             :  * Returns true if the file was successfully sent, false if 'missing_ok',
    1571             :  * and the file did not exist.
    1572             :  */
    1573             : static bool
    1574      299640 : sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
    1575             :          struct stat *statbuf, bool missing_ok, Oid dboid, Oid spcoid,
    1576             :          RelFileNumber relfilenumber, unsigned segno,
    1577             :          backup_manifest_info *manifest, unsigned num_incremental_blocks,
    1578             :          BlockNumber *incremental_blocks, unsigned truncation_block_length)
    1579             : {
    1580             :     int         fd;
    1581      299640 :     BlockNumber blkno = 0;
    1582      299640 :     int         checksum_failures = 0;
    1583             :     off_t       cnt;
    1584      299640 :     pgoff_t     bytes_done = 0;
    1585      299640 :     bool        verify_checksum = false;
    1586             :     pg_checksum_context checksum_ctx;
    1587      299640 :     int         ibindex = 0;
    1588             : 
    1589      299640 :     if (pg_checksum_init(&checksum_ctx, manifest->checksum_type) < 0)
    1590           0 :         elog(ERROR, "could not initialize checksum of file \"%s\"",
    1591             :              readfilename);
    1592             : 
    1593      299640 :     fd = OpenTransientFile(readfilename, O_RDONLY | PG_BINARY);
    1594      299640 :     if (fd < 0)
    1595             :     {
    1596           0 :         if (errno == ENOENT && missing_ok)
    1597           0 :             return false;
    1598           0 :         ereport(ERROR,
    1599             :                 (errcode_for_file_access(),
    1600             :                  errmsg("could not open file \"%s\": %m", readfilename)));
    1601             :     }
    1602             : 
    1603      299640 :     _tarWriteHeader(sink, tarfilename, NULL, statbuf, false);
    1604             : 
    1605             :     /*
    1606             :      * Checksums are verified in multiples of BLCKSZ, so the buffer length
    1607             :      * should be a multiple of the block size as well.
    1608             :      */
    1609             :     Assert((sink->bbs_buffer_length % BLCKSZ) == 0);
    1610             : 
    1611             :     /*
    1612             :      * If we weren't told not to verify checksums, and if checksums are
    1613             :      * enabled for this cluster, and if this is a relation file, then verify
    1614             :      * the checksum.
    1615             :      */
    1616      299638 :     if (!noverify_checksums && DataChecksumsEnabled() &&
    1617             :         RelFileNumberIsValid(relfilenumber))
    1618      292396 :         verify_checksum = true;
    1619             : 
    1620             :     /*
    1621             :      * If we're sending an incremental file, write the file header.
    1622             :      */
    1623      299638 :     if (incremental_blocks != NULL)
    1624             :     {
    1625       12002 :         unsigned    magic = INCREMENTAL_MAGIC;
    1626       12002 :         size_t      header_bytes_done = 0;
    1627             :         char        padding[BLCKSZ];
    1628             :         size_t      paddinglen;
    1629             : 
    1630             :         /* Emit header data. */
    1631       12002 :         push_to_sink(sink, &checksum_ctx, &header_bytes_done,
    1632             :                      &magic, sizeof(magic));
    1633       12002 :         push_to_sink(sink, &checksum_ctx, &header_bytes_done,
    1634             :                      &num_incremental_blocks, sizeof(num_incremental_blocks));
    1635       12002 :         push_to_sink(sink, &checksum_ctx, &header_bytes_done,
    1636             :                      &truncation_block_length, sizeof(truncation_block_length));
    1637       12002 :         push_to_sink(sink, &checksum_ctx, &header_bytes_done,
    1638             :                      incremental_blocks,
    1639             :                      sizeof(BlockNumber) * num_incremental_blocks);
    1640             : 
    1641             :         /*
    1642             :          * Add padding to align header to a multiple of BLCKSZ, but only if
    1643             :          * the incremental file has some blocks, and the alignment is actually
    1644             :          * needed (i.e. header is not already a multiple of BLCKSZ). If there
    1645             :          * are no blocks we don't want to make the file unnecessarily large,
    1646             :          * as that might make some filesystem optimizations impossible.
    1647             :          */
    1648       12002 :         if ((num_incremental_blocks > 0) && (header_bytes_done % BLCKSZ != 0))
    1649             :         {
    1650          46 :             paddinglen = (BLCKSZ - (header_bytes_done % BLCKSZ));
    1651             : 
    1652          46 :             memset(padding, 0, paddinglen);
    1653          46 :             bytes_done += paddinglen;
    1654             : 
    1655          46 :             push_to_sink(sink, &checksum_ctx, &header_bytes_done,
    1656             :                          padding, paddinglen);
    1657             :         }
    1658             : 
    1659             :         /* Flush out any data still in the buffer so it's again empty. */
    1660       12002 :         if (header_bytes_done > 0)
    1661             :         {
    1662       12002 :             bbsink_archive_contents(sink, header_bytes_done);
    1663       12002 :             if (pg_checksum_update(&checksum_ctx,
    1664       12002 :                                    (uint8 *) sink->bbs_buffer,
    1665             :                                    header_bytes_done) < 0)
    1666           0 :                 elog(ERROR, "could not update checksum of base backup");
    1667             :         }
    1668             : 
    1669             :         /* Update our notion of file position. */
    1670       12002 :         bytes_done += sizeof(magic);
    1671       12002 :         bytes_done += sizeof(num_incremental_blocks);
    1672       12002 :         bytes_done += sizeof(truncation_block_length);
    1673       12002 :         bytes_done += sizeof(BlockNumber) * num_incremental_blocks;
    1674             :     }
    1675             : 
    1676             :     /*
    1677             :      * Loop until we read the amount of data the caller told us to expect. The
    1678             :      * file could be longer, if it was extended while we were sending it, but
    1679             :      * for a base backup we can ignore such extended data. It will be restored
    1680             :      * from WAL.
    1681             :      */
    1682             :     while (1)
    1683             :     {
    1684             :         /*
    1685             :          * Determine whether we've read all the data that we need, and if not,
    1686             :          * read some more.
    1687             :          */
    1688      644870 :         if (incremental_blocks == NULL)
    1689             :         {
    1690      632792 :             size_t      remaining = statbuf->st_size - bytes_done;
    1691             : 
    1692             :             /*
    1693             :              * If we've read the required number of bytes, then it's time to
    1694             :              * stop.
    1695             :              */
    1696      632792 :             if (bytes_done >= statbuf->st_size)
    1697      287636 :                 break;
    1698             : 
    1699             :             /*
    1700             :              * Read as many bytes as will fit in the buffer, or however many
    1701             :              * are left to read, whichever is less.
    1702             :              */
    1703      345156 :             cnt = read_file_data_into_buffer(sink, readfilename, fd,
    1704             :                                              bytes_done, remaining,
    1705      345156 :                                              blkno + segno * RELSEG_SIZE,
    1706             :                                              verify_checksum,
    1707             :                                              &checksum_failures);
    1708             :         }
    1709             :         else
    1710             :         {
    1711             :             BlockNumber relative_blkno;
    1712             : 
    1713             :             /*
    1714             :              * If we've read all the blocks, then it's time to stop.
    1715             :              */
    1716       12078 :             if (ibindex >= num_incremental_blocks)
    1717       12002 :                 break;
    1718             : 
    1719             :             /*
    1720             :              * Read just one block, whichever one is the next that we're
    1721             :              * supposed to include.
    1722             :              */
    1723          76 :             relative_blkno = incremental_blocks[ibindex++];
    1724          76 :             cnt = read_file_data_into_buffer(sink, readfilename, fd,
    1725          76 :                                              relative_blkno * BLCKSZ,
    1726             :                                              BLCKSZ,
    1727          76 :                                              relative_blkno + segno * RELSEG_SIZE,
    1728             :                                              verify_checksum,
    1729             :                                              &checksum_failures);
    1730             : 
    1731             :             /*
    1732             :              * If we get a partial read, that must mean that the relation is
    1733             :              * being truncated. Ultimately, it should be truncated to a
    1734             :              * multiple of BLCKSZ, since this path should only be reached for
    1735             :              * relation files, but we might transiently observe an
    1736             :              * intermediate value.
    1737             :              *
    1738             :              * It should be fine to treat this just as if the entire block had
    1739             :              * been truncated away - i.e. fill this and all later blocks with
    1740             :              * zeroes. WAL replay will fix things up.
    1741             :              */
    1742          76 :             if (cnt < BLCKSZ)
    1743           0 :                 break;
    1744             :         }
    1745             : 
    1746             :         /*
    1747             :          * If the amount of data we were able to read was not a multiple of
    1748             :          * BLCKSZ, we cannot verify checksums, which are block-level.
    1749             :          */
    1750      345232 :         if (verify_checksum && (cnt % BLCKSZ != 0))
    1751             :         {
    1752           0 :             ereport(WARNING,
    1753             :                     (errmsg("could not verify checksum in file \"%s\", block "
    1754             :                             "%u: read buffer size %d and page size %d "
    1755             :                             "differ",
    1756             :                             readfilename, blkno, (int) cnt, BLCKSZ)));
    1757           0 :             verify_checksum = false;
    1758             :         }
    1759             : 
    1760             :         /*
    1761             :          * If we hit end-of-file, a concurrent truncation must have occurred.
    1762             :          * That's not an error condition, because WAL replay will fix things
    1763             :          * up.
    1764             :          */
    1765      345232 :         if (cnt == 0)
    1766           0 :             break;
    1767             : 
    1768             :         /* Update block number and # of bytes done for next loop iteration. */
    1769      345232 :         blkno += cnt / BLCKSZ;
    1770      345232 :         bytes_done += cnt;
    1771             : 
    1772             :         /*
    1773             :          * Make sure incremental files with block data are properly aligned
    1774             :          * (header is a multiple of BLCKSZ, blocks are BLCKSZ too).
    1775             :          */
    1776             :         Assert(!((incremental_blocks != NULL && num_incremental_blocks > 0) &&
    1777             :                  (bytes_done % BLCKSZ != 0)));
    1778             : 
    1779             :         /* Archive the data we just read. */
    1780      345232 :         bbsink_archive_contents(sink, cnt);
    1781             : 
    1782             :         /* Also feed it to the checksum machinery. */
    1783      345232 :         if (pg_checksum_update(&checksum_ctx,
    1784      345232 :                                (uint8 *) sink->bbs_buffer, cnt) < 0)
    1785           0 :             elog(ERROR, "could not update checksum of base backup");
    1786             :     }
    1787             : 
    1788             :     /* If the file was truncated while we were sending it, pad it with zeros */
    1789      299638 :     while (bytes_done < statbuf->st_size)
    1790             :     {
    1791           0 :         size_t      remaining = statbuf->st_size - bytes_done;
    1792           0 :         size_t      nbytes = Min(sink->bbs_buffer_length, remaining);
    1793             : 
    1794           0 :         MemSet(sink->bbs_buffer, 0, nbytes);
    1795           0 :         if (pg_checksum_update(&checksum_ctx,
    1796           0 :                                (uint8 *) sink->bbs_buffer,
    1797             :                                nbytes) < 0)
    1798           0 :             elog(ERROR, "could not update checksum of base backup");
    1799           0 :         bbsink_archive_contents(sink, nbytes);
    1800           0 :         bytes_done += nbytes;
    1801             :     }
    1802             : 
    1803             :     /*
    1804             :      * Pad to a block boundary, per tar format requirements. (This small piece
    1805             :      * of data is probably not worth throttling, and is not checksummed
    1806             :      * because it's not actually part of the file.)
    1807             :      */
    1808      299638 :     _tarWritePadding(sink, bytes_done);
    1809             : 
    1810      299638 :     CloseTransientFile(fd);
    1811             : 
    1812      299638 :     if (checksum_failures > 1)
    1813             :     {
    1814           4 :         ereport(WARNING,
    1815             :                 (errmsg_plural("file \"%s\" has a total of %d checksum verification failure",
    1816             :                                "file \"%s\" has a total of %d checksum verification failures",
    1817             :                                checksum_failures,
    1818             :                                readfilename, checksum_failures)));
    1819             : 
    1820           4 :         pgstat_report_checksum_failures_in_db(dboid, checksum_failures);
    1821             :     }
    1822             : 
    1823      299638 :     total_checksum_failures += checksum_failures;
    1824             : 
    1825      299638 :     AddFileToBackupManifest(manifest, spcoid, tarfilename, statbuf->st_size,
    1826      299638 :                             (pg_time_t) statbuf->st_mtime, &checksum_ctx);
    1827             : 
    1828      299638 :     return true;
    1829             : }
    1830             : 
    1831             : /*
    1832             :  * Read some more data from the file into the bbsink's buffer, verifying
    1833             :  * checksums as required.
    1834             :  *
    1835             :  * 'offset' is the file offset from which we should begin to read, and
    1836             :  * 'length' is the amount of data that should be read. The actual amount
    1837             :  * of data read will be less than the requested amount if the bbsink's
    1838             :  * buffer isn't big enough to hold it all, or if the underlying file has
    1839             :  * been truncated. The return value is the number of bytes actually read.
    1840             :  *
    1841             :  * 'blkno' is the block number of the first page in the bbsink's buffer
    1842             :  * relative to the start of the relation.
    1843             :  *
    1844             :  * 'verify_checksum' indicates whether we should try to verify checksums
    1845             :  * for the blocks we read. If we do this, we'll update *checksum_failures
    1846             :  * and issue warnings as appropriate.
    1847             :  */
    1848             : static off_t
    1849      345232 : read_file_data_into_buffer(bbsink *sink, const char *readfilename, int fd,
    1850             :                            off_t offset, size_t length, BlockNumber blkno,
    1851             :                            bool verify_checksum, int *checksum_failures)
    1852             : {
    1853             :     off_t       cnt;
    1854             :     int         i;
    1855             :     char       *page;
    1856             : 
    1857             :     /* Try to read some more data. */
    1858      345232 :     cnt = basebackup_read_file(fd, sink->bbs_buffer,
    1859      345232 :                                Min(sink->bbs_buffer_length, length),
    1860             :                                offset, readfilename, true);
    1861             : 
    1862             :     /* Can't verify checksums if read length is not a multiple of BLCKSZ. */
    1863      345232 :     if (!verify_checksum || (cnt % BLCKSZ) != 0)
    1864        7680 :         return cnt;
    1865             : 
    1866             :     /* Verify checksum for each block. */
    1867     1168884 :     for (i = 0; i < cnt / BLCKSZ; i++)
    1868             :     {
    1869             :         int         reread_cnt;
    1870             :         uint16      expected_checksum;
    1871             : 
    1872      831332 :         page = sink->bbs_buffer + BLCKSZ * i;
    1873             : 
    1874             :         /* If the page is OK, go on to the next one. */
    1875      831332 :         if (verify_page_checksum(page, sink->bbs_state->startptr, blkno + i,
    1876             :                                  &expected_checksum))
    1877      831304 :             continue;
    1878             : 
    1879             :         /*
    1880             :          * Retry the block on the first failure.  It's possible that we read
    1881             :          * the first 4K page of the block just before postgres updated the
    1882             :          * entire block so it ends up looking torn to us. If, before we retry
    1883             :          * the read, the concurrent write of the block finishes, the page LSN
    1884             :          * will be updated and we'll realize that we should ignore this block.
    1885             :          *
    1886             :          * There's no guarantee that this will actually happen, though: the
    1887             :          * torn write could take an arbitrarily long time to complete.
    1888             :          * Retrying multiple times wouldn't fix this problem, either, though
    1889             :          * it would reduce the chances of it happening in practice. The only
    1890             :          * real fix here seems to be to have some kind of interlock that
    1891             :          * allows us to wait until we can be certain that no write to the
    1892             :          * block is in progress. Since we don't have any such thing right now,
    1893             :          * we just do this and hope for the best.
    1894             :          */
    1895          28 :         reread_cnt =
    1896          28 :             basebackup_read_file(fd, sink->bbs_buffer + BLCKSZ * i,
    1897          28 :                                  BLCKSZ, offset + BLCKSZ * i,
    1898             :                                  readfilename, false);
    1899          28 :         if (reread_cnt == 0)
    1900             :         {
    1901             :             /*
    1902             :              * If we hit end-of-file, a concurrent truncation must have
    1903             :              * occurred, so reduce cnt to reflect only the blocks already
    1904             :              * processed and break out of this loop.
    1905             :              */
    1906           0 :             cnt = BLCKSZ * i;
    1907           0 :             break;
    1908             :         }
    1909             : 
    1910             :         /* If the page now looks OK, go on to the next one. */
    1911          28 :         if (verify_page_checksum(page, sink->bbs_state->startptr, blkno + i,
    1912             :                                  &expected_checksum))
    1913           0 :             continue;
    1914             : 
    1915             :         /* Handle checksum failure. */
    1916          28 :         (*checksum_failures)++;
    1917          28 :         if (*checksum_failures <= 5)
    1918          24 :             ereport(WARNING,
    1919             :                     (errmsg("checksum verification failed in "
    1920             :                             "file \"%s\", block %u: calculated "
    1921             :                             "%X but expected %X",
    1922             :                             readfilename, blkno + i, expected_checksum,
    1923             :                             ((PageHeader) page)->pd_checksum)));
    1924          28 :         if (*checksum_failures == 5)
    1925           4 :             ereport(WARNING,
    1926             :                     (errmsg("further checksum verification "
    1927             :                             "failures in file \"%s\" will not "
    1928             :                             "be reported", readfilename)));
    1929             :     }
    1930             : 
    1931      337552 :     return cnt;
    1932             : }
    1933             : 
    1934             : /*
    1935             :  * Push data into a bbsink.
    1936             :  *
    1937             :  * It's better, when possible, to read data directly into the bbsink's buffer,
    1938             :  * rather than using this function to copy it into the buffer; this function is
    1939             :  * for cases where that approach is not practical.
    1940             :  *
    1941             :  * bytes_done should point to a count of the number of bytes that are
    1942             :  * currently used in the bbsink's buffer. Upon return, the bytes identified by
    1943             :  * data and length will have been copied into the bbsink's buffer, flushing
    1944             :  * as required, and *bytes_done will have been updated accordingly. If the
    1945             :  * buffer was flushed, the previous contents will also have been fed to
    1946             :  * checksum_ctx.
    1947             :  *
    1948             :  * Note that after one or more calls to this function it is the caller's
    1949             :  * responsibility to perform any required final flush.
    1950             :  */
    1951             : static void
    1952       48054 : push_to_sink(bbsink *sink, pg_checksum_context *checksum_ctx,
    1953             :              size_t *bytes_done, void *data, size_t length)
    1954             : {
    1955       48054 :     while (length > 0)
    1956             :     {
    1957             :         size_t      bytes_to_copy;
    1958             : 
    1959             :         /*
    1960             :          * We use < here rather than <= so that if the data exactly fills the
    1961             :          * remaining buffer space, we trigger a flush now.
    1962             :          */
    1963       36098 :         if (length < sink->bbs_buffer_length - *bytes_done)
    1964             :         {
    1965             :             /* Append remaining data to buffer. */
    1966       36098 :             memcpy(sink->bbs_buffer + *bytes_done, data, length);
    1967       36098 :             *bytes_done += length;
    1968       36098 :             return;
    1969             :         }
    1970             : 
    1971             :         /* Copy until buffer is full and flush it. */
    1972           0 :         bytes_to_copy = sink->bbs_buffer_length - *bytes_done;
    1973           0 :         memcpy(sink->bbs_buffer + *bytes_done, data, bytes_to_copy);
    1974           0 :         data = ((char *) data) + bytes_to_copy;
    1975           0 :         length -= bytes_to_copy;
    1976           0 :         bbsink_archive_contents(sink, sink->bbs_buffer_length);
    1977           0 :         if (pg_checksum_update(checksum_ctx, (uint8 *) sink->bbs_buffer,
    1978             :                                sink->bbs_buffer_length) < 0)
    1979           0 :             elog(ERROR, "could not update checksum");
    1980           0 :         *bytes_done = 0;
    1981             :     }
    1982             : }
    1983             : 
    1984             : /*
    1985             :  * Try to verify the checksum for the provided page, if it seems appropriate
    1986             :  * to do so.
    1987             :  *
    1988             :  * Returns true if verification succeeds or if we decide not to check it,
    1989             :  * and false if verification fails. When return false, it also sets
    1990             :  * *expected_checksum to the computed value.
    1991             :  */
    1992             : static bool
    1993      831360 : verify_page_checksum(Page page, XLogRecPtr start_lsn, BlockNumber blkno,
    1994             :                      uint16 *expected_checksum)
    1995             : {
    1996             :     PageHeader  phdr;
    1997             :     uint16      checksum;
    1998             : 
    1999             :     /*
    2000             :      * Only check pages which have not been modified since the start of the
    2001             :      * base backup. Otherwise, they might have been written only halfway and
    2002             :      * the checksum would not be valid.  However, replaying WAL would
    2003             :      * reinstate the correct page in this case. We also skip completely new
    2004             :      * pages, since they don't have a checksum yet.
    2005             :      */
    2006      831360 :     if (PageIsNew(page) || PageGetLSN(page) >= start_lsn)
    2007        2028 :         return true;
    2008             : 
    2009             :     /* Perform the actual checksum calculation. */
    2010      829332 :     checksum = pg_checksum_page(page, blkno);
    2011             : 
    2012             :     /* See whether it matches the value from the page. */
    2013      829332 :     phdr = (PageHeader) page;
    2014      829332 :     if (phdr->pd_checksum == checksum)
    2015      829276 :         return true;
    2016          56 :     *expected_checksum = checksum;
    2017          56 :     return false;
    2018             : }
    2019             : 
    2020             : static int64
    2021      316488 : _tarWriteHeader(bbsink *sink, const char *filename, const char *linktarget,
    2022             :                 struct stat *statbuf, bool sizeonly)
    2023             : {
    2024             :     enum tarError rc;
    2025             : 
    2026      316488 :     if (!sizeonly)
    2027             :     {
    2028             :         /*
    2029             :          * As of this writing, the smallest supported block size is 1kB, which
    2030             :          * is twice TAR_BLOCK_SIZE. Since the buffer size is required to be a
    2031             :          * multiple of BLCKSZ, it should be safe to assume that the buffer is
    2032             :          * large enough to fit an entire tar block. We double-check by means
    2033             :          * of these assertions.
    2034             :          */
    2035             :         StaticAssertDecl(TAR_BLOCK_SIZE <= BLCKSZ,
    2036             :                          "BLCKSZ too small for tar block");
    2037             :         Assert(sink->bbs_buffer_length >= TAR_BLOCK_SIZE);
    2038             : 
    2039      308196 :         rc = tarCreateHeader(sink->bbs_buffer, filename, linktarget,
    2040             :                              statbuf->st_size, statbuf->st_mode,
    2041             :                              statbuf->st_uid, statbuf->st_gid,
    2042             :                              statbuf->st_mtime);
    2043             : 
    2044      308196 :         switch (rc)
    2045             :         {
    2046      308194 :             case TAR_OK:
    2047      308194 :                 break;
    2048           2 :             case TAR_NAME_TOO_LONG:
    2049           2 :                 ereport(ERROR,
    2050             :                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2051             :                          errmsg("file name too long for tar format: \"%s\"",
    2052             :                                 filename)));
    2053             :                 break;
    2054           0 :             case TAR_SYMLINK_TOO_LONG:
    2055           0 :                 ereport(ERROR,
    2056             :                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2057             :                          errmsg("symbolic link target too long for tar format: "
    2058             :                                 "file name \"%s\", target \"%s\"",
    2059             :                                 filename, linktarget)));
    2060             :                 break;
    2061           0 :             default:
    2062           0 :                 elog(ERROR, "unrecognized tar error: %d", rc);
    2063             :         }
    2064             : 
    2065      308194 :         bbsink_archive_contents(sink, TAR_BLOCK_SIZE);
    2066             :     }
    2067             : 
    2068      316484 :     return TAR_BLOCK_SIZE;
    2069             : }
    2070             : 
    2071             : /*
    2072             :  * Pad with zero bytes out to a multiple of TAR_BLOCK_SIZE.
    2073             :  */
    2074             : static void
    2075      300026 : _tarWritePadding(bbsink *sink, int len)
    2076             : {
    2077      300026 :     int         pad = tarPaddingBytesRequired(len);
    2078             : 
    2079             :     /*
    2080             :      * As in _tarWriteHeader, it should be safe to assume that the buffer is
    2081             :      * large enough that we don't need to do this in multiple chunks.
    2082             :      */
    2083             :     Assert(sink->bbs_buffer_length >= TAR_BLOCK_SIZE);
    2084             :     Assert(pad <= TAR_BLOCK_SIZE);
    2085             : 
    2086      300026 :     if (pad > 0)
    2087             :     {
    2088       70164 :         MemSet(sink->bbs_buffer, 0, pad);
    2089       16372 :         bbsink_archive_contents(sink, pad);
    2090             :     }
    2091      300026 : }
    2092             : 
    2093             : /*
    2094             :  * If the entry in statbuf is a link, then adjust statbuf to make it look like a
    2095             :  * directory, so that it will be written that way.
    2096             :  */
    2097             : static void
    2098        4912 : convert_link_to_directory(const char *pathbuf, struct stat *statbuf)
    2099             : {
    2100             :     /* If symlink, write it as a directory anyway */
    2101        4912 :     if (S_ISLNK(statbuf->st_mode))
    2102         136 :         statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
    2103        4912 : }
    2104             : 
    2105             : /*
    2106             :  * Read some data from a file, setting a wait event and reporting any error
    2107             :  * encountered.
    2108             :  *
    2109             :  * If partial_read_ok is false, also report an error if the number of bytes
    2110             :  * read is not equal to the number of bytes requested.
    2111             :  *
    2112             :  * Returns the number of bytes read.
    2113             :  */
    2114             : static ssize_t
    2115      358572 : basebackup_read_file(int fd, char *buf, size_t nbytes, off_t offset,
    2116             :                      const char *filename, bool partial_read_ok)
    2117             : {
    2118             :     ssize_t     rc;
    2119             : 
    2120      358572 :     pgstat_report_wait_start(WAIT_EVENT_BASEBACKUP_READ);
    2121      358572 :     rc = pg_pread(fd, buf, nbytes, offset);
    2122      358572 :     pgstat_report_wait_end();
    2123             : 
    2124      358572 :     if (rc < 0)
    2125           0 :         ereport(ERROR,
    2126             :                 (errcode_for_file_access(),
    2127             :                  errmsg("could not read file \"%s\": %m", filename)));
    2128      358572 :     if (!partial_read_ok && rc > 0 && rc != nbytes)
    2129           0 :         ereport(ERROR,
    2130             :                 (errcode_for_file_access(),
    2131             :                  errmsg("could not read file \"%s\": read %zd of %zu",
    2132             :                         filename, rc, nbytes)));
    2133             : 
    2134      358572 :     return rc;
    2135             : }

Generated by: LCOV version 1.14