LCOV - differential code coverage report
Current view: top level - src/bin/pg_basebackup - astreamer_inject.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 82.7 % 75 62 13 62
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 5 5 5
Baseline: lcov-20250906-005545-baseline Branches: 68.0 % 25 17 8 17
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(360..) days: 82.7 % 75 62 13 62
Function coverage date bins:
(360..) days: 100.0 % 5 5 5
Branch coverage date bins:
(360..) days: 68.0 % 25 17 8 17

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * astreamer_inject.c
                                  4                 :                :  *
                                  5                 :                :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
                                  6                 :                :  *
                                  7                 :                :  * IDENTIFICATION
                                  8                 :                :  *        src/bin/pg_basebackup/astreamer_inject.c
                                  9                 :                :  *-------------------------------------------------------------------------
                                 10                 :                :  */
                                 11                 :                : 
                                 12                 :                : #include "postgres_fe.h"
                                 13                 :                : 
                                 14                 :                : #include "astreamer_inject.h"
                                 15                 :                : #include "common/file_perm.h"
                                 16                 :                : #include "common/logging.h"
                                 17                 :                : 
                                 18                 :                : typedef struct astreamer_recovery_injector
                                 19                 :                : {
                                 20                 :                :     astreamer   base;
                                 21                 :                :     bool        skip_file;
                                 22                 :                :     bool        is_recovery_guc_supported;
                                 23                 :                :     bool        is_postgresql_auto_conf;
                                 24                 :                :     bool        found_postgresql_auto_conf;
                                 25                 :                :     PQExpBuffer recoveryconfcontents;
                                 26                 :                :     astreamer_member member;
                                 27                 :                : } astreamer_recovery_injector;
                                 28                 :                : 
                                 29                 :                : static void astreamer_recovery_injector_content(astreamer *streamer,
                                 30                 :                :                                                 astreamer_member *member,
                                 31                 :                :                                                 const char *data, int len,
                                 32                 :                :                                                 astreamer_archive_context context);
                                 33                 :                : static void astreamer_recovery_injector_finalize(astreamer *streamer);
                                 34                 :                : static void astreamer_recovery_injector_free(astreamer *streamer);
                                 35                 :                : 
                                 36                 :                : static const astreamer_ops astreamer_recovery_injector_ops = {
                                 37                 :                :     .content = astreamer_recovery_injector_content,
                                 38                 :                :     .finalize = astreamer_recovery_injector_finalize,
                                 39                 :                :     .free = astreamer_recovery_injector_free
                                 40                 :                : };
                                 41                 :                : 
                                 42                 :                : /*
                                 43                 :                :  * Create a astreamer that can edit recoverydata into an archive stream.
                                 44                 :                :  *
                                 45                 :                :  * The input should be a series of typed chunks (not ASTREAMER_UNKNOWN) as
                                 46                 :                :  * per the conventions described in astreamer.h; the chunks forwarded to
                                 47                 :                :  * the next astreamer will be similarly typed, but the
                                 48                 :                :  * ASTREAMER_MEMBER_HEADER chunks may be zero-length in cases where we've
                                 49                 :                :  * edited the archive stream.
                                 50                 :                :  *
                                 51                 :                :  * Our goal is to do one of the following three things with the content passed
                                 52                 :                :  * via recoveryconfcontents: (1) if is_recovery_guc_supported is false, then
                                 53                 :                :  * put the content into recovery.conf, replacing any existing archive member
                                 54                 :                :  * by that name; (2) if is_recovery_guc_supported is true and
                                 55                 :                :  * postgresql.auto.conf exists in the archive, then append the content
                                 56                 :                :  * provided to the existing file; and (3) if is_recovery_guc_supported is
                                 57                 :                :  * true but postgresql.auto.conf does not exist in the archive, then create
                                 58                 :                :  * it with the specified content.
                                 59                 :                :  *
                                 60                 :                :  * In addition, if is_recovery_guc_supported is true, then we create a
                                 61                 :                :  * zero-length standby.signal file, dropping any file with that name from
                                 62                 :                :  * the archive.
                                 63                 :                :  */
                                 64                 :                : astreamer *
  397 rhaas@postgresql.org       65                 :CBC           3 : astreamer_recovery_injector_new(astreamer *next,
                                 66                 :                :                                 bool is_recovery_guc_supported,
                                 67                 :                :                                 PQExpBuffer recoveryconfcontents)
                                 68                 :                : {
                                 69                 :                :     astreamer_recovery_injector *streamer;
                                 70                 :                : 
                                 71                 :              3 :     streamer = palloc0(sizeof(astreamer_recovery_injector));
                                 72                 :              3 :     *((const astreamer_ops **) &streamer->base.bbs_ops) =
                                 73                 :                :         &astreamer_recovery_injector_ops;
 1401                            74                 :              3 :     streamer->base.bbs_next = next;
                                 75                 :              3 :     streamer->is_recovery_guc_supported = is_recovery_guc_supported;
                                 76                 :              3 :     streamer->recoveryconfcontents = recoveryconfcontents;
                                 77                 :                : 
                                 78                 :              3 :     return &streamer->base;
                                 79                 :                : }
                                 80                 :                : 
                                 81                 :                : /*
                                 82                 :                :  * Handle each chunk of tar content while injecting recovery configuration.
                                 83                 :                :  */
                                 84                 :                : static void
  397                            85                 :           9569 : astreamer_recovery_injector_content(astreamer *streamer,
                                 86                 :                :                                     astreamer_member *member,
                                 87                 :                :                                     const char *data, int len,
                                 88                 :                :                                     astreamer_archive_context context)
                                 89                 :                : {
                                 90                 :                :     astreamer_recovery_injector *mystreamer;
                                 91                 :                : 
                                 92                 :           9569 :     mystreamer = (astreamer_recovery_injector *) streamer;
                                 93   [ +  +  -  + ]:           9569 :     Assert(member != NULL || context == ASTREAMER_ARCHIVE_TRAILER);
                                 94                 :                : 
 1401                            95   [ +  +  +  +  :           9569 :     switch (context)
                                                 - ]
                                 96                 :                :     {
  397                            97                 :           2988 :         case ASTREAMER_MEMBER_HEADER:
                                 98                 :                :             /* Must copy provided data so we have the option to modify it. */
                                 99                 :           2988 :             memcpy(&mystreamer->member, member, sizeof(astreamer_member));
                                100                 :                : 
                                101                 :                :             /*
                                102                 :                :              * On v12+, skip standby.signal and edit postgresql.auto.conf; on
                                103                 :                :              * older versions, skip recovery.conf.
                                104                 :                :              */
 1401                           105         [ +  - ]:           2988 :             if (mystreamer->is_recovery_guc_supported)
                                106                 :                :             {
                                107                 :           2988 :                 mystreamer->skip_file =
                                108                 :           2988 :                     (strcmp(member->pathname, "standby.signal") == 0);
                                109                 :           2988 :                 mystreamer->is_postgresql_auto_conf =
                                110                 :           2988 :                     (strcmp(member->pathname, "postgresql.auto.conf") == 0);
                                111         [ +  + ]:           2988 :                 if (mystreamer->is_postgresql_auto_conf)
                                112                 :                :                 {
                                113                 :                :                     /* Remember we saw it so we don't add it again. */
                                114                 :              3 :                     mystreamer->found_postgresql_auto_conf = true;
                                115                 :                : 
                                116                 :                :                     /* Increment length by data to be injected. */
                                117                 :              3 :                     mystreamer->member.size +=
                                118                 :              3 :                         mystreamer->recoveryconfcontents->len;
                                119                 :                : 
                                120                 :                :                     /*
                                121                 :                :                      * Zap data and len because the archive header is no
                                122                 :                :                      * longer valid; some subsequent astreamer must regenerate
                                123                 :                :                      * it if it's necessary.
                                124                 :                :                      */
                                125                 :              3 :                     data = NULL;
                                126                 :              3 :                     len = 0;
                                127                 :                :                 }
                                128                 :                :             }
                                129                 :                :             else
 1401 rhaas@postgresql.org      130                 :UBC           0 :                 mystreamer->skip_file =
                                131                 :              0 :                     (strcmp(member->pathname, "recovery.conf") == 0);
                                132                 :                : 
                                133                 :                :             /* Do not forward if the file is to be skipped. */
 1401 rhaas@postgresql.org      134         [ -  + ]:CBC        2988 :             if (mystreamer->skip_file)
 1401 rhaas@postgresql.org      135                 :UBC           0 :                 return;
 1401 rhaas@postgresql.org      136                 :CBC        2988 :             break;
                                137                 :                : 
  397                           138                 :           3590 :         case ASTREAMER_MEMBER_CONTENTS:
                                139                 :                :             /* Do not forward if the file is to be skipped. */
 1401                           140         [ -  + ]:           3590 :             if (mystreamer->skip_file)
 1401 rhaas@postgresql.org      141                 :UBC           0 :                 return;
 1401 rhaas@postgresql.org      142                 :CBC        3590 :             break;
                                143                 :                : 
  397                           144                 :           2988 :         case ASTREAMER_MEMBER_TRAILER:
                                145                 :                :             /* Do not forward it the file is to be skipped. */
 1401                           146         [ -  + ]:           2988 :             if (mystreamer->skip_file)
 1401 rhaas@postgresql.org      147                 :UBC           0 :                 return;
                                148                 :                : 
                                149                 :                :             /* Append provided content to whatever we already sent. */
 1401 rhaas@postgresql.org      150         [ +  + ]:CBC        2988 :             if (mystreamer->is_postgresql_auto_conf)
  397                           151                 :              3 :                 astreamer_content(mystreamer->base.bbs_next, member,
                                152                 :              3 :                                   mystreamer->recoveryconfcontents->data,
                                153                 :              3 :                                   mystreamer->recoveryconfcontents->len,
                                154                 :                :                                   ASTREAMER_MEMBER_CONTENTS);
 1401                           155                 :           2988 :             break;
                                156                 :                : 
  397                           157                 :              3 :         case ASTREAMER_ARCHIVE_TRAILER:
 1401                           158         [ +  - ]:              3 :             if (mystreamer->is_recovery_guc_supported)
                                159                 :                :             {
                                160                 :                :                 /*
                                161                 :                :                  * If we didn't already find (and thus modify)
                                162                 :                :                  * postgresql.auto.conf, inject it as an additional archive
                                163                 :                :                  * member now.
                                164                 :                :                  */
                                165         [ -  + ]:              3 :                 if (!mystreamer->found_postgresql_auto_conf)
  397 rhaas@postgresql.org      166                 :UBC           0 :                     astreamer_inject_file(mystreamer->base.bbs_next,
                                167                 :                :                                           "postgresql.auto.conf",
                                168                 :              0 :                                           mystreamer->recoveryconfcontents->data,
                                169                 :              0 :                                           mystreamer->recoveryconfcontents->len);
                                170                 :                : 
                                171                 :                :                 /* Inject empty standby.signal file. */
  397 rhaas@postgresql.org      172                 :CBC           3 :                 astreamer_inject_file(mystreamer->base.bbs_next,
                                173                 :                :                                       "standby.signal", "", 0);
                                174                 :                :             }
                                175                 :                :             else
                                176                 :                :             {
                                177                 :                :                 /* Inject recovery.conf file with specified contents. */
  397 rhaas@postgresql.org      178                 :UBC           0 :                 astreamer_inject_file(mystreamer->base.bbs_next,
                                179                 :                :                                       "recovery.conf",
                                180                 :              0 :                                       mystreamer->recoveryconfcontents->data,
                                181                 :              0 :                                       mystreamer->recoveryconfcontents->len);
                                182                 :                :             }
                                183                 :                : 
                                184                 :                :             /* Nothing to do here. */
 1401 rhaas@postgresql.org      185                 :CBC           3 :             break;
                                186                 :                : 
 1401 rhaas@postgresql.org      187                 :UBC           0 :         default:
                                188                 :                :             /* Shouldn't happen. */
 1247 tgl@sss.pgh.pa.us         189                 :              0 :             pg_fatal("unexpected state while injecting recovery settings");
                                190                 :                :     }
                                191                 :                : 
  397 rhaas@postgresql.org      192                 :CBC        9569 :     astreamer_content(mystreamer->base.bbs_next, &mystreamer->member,
                                193                 :                :                       data, len, context);
                                194                 :                : }
                                195                 :                : 
                                196                 :                : /*
                                197                 :                :  * End-of-stream processing for this astreamer.
                                198                 :                :  */
                                199                 :                : static void
                                200                 :              3 : astreamer_recovery_injector_finalize(astreamer *streamer)
                                201                 :                : {
                                202                 :              3 :     astreamer_finalize(streamer->bbs_next);
 1401                           203                 :              3 : }
                                204                 :                : 
                                205                 :                : /*
                                206                 :                :  * Free memory associated with this astreamer.
                                207                 :                :  */
                                208                 :                : static void
  397                           209                 :              3 : astreamer_recovery_injector_free(astreamer *streamer)
                                210                 :                : {
                                211                 :              3 :     astreamer_free(streamer->bbs_next);
 1401                           212                 :              3 :     pfree(streamer);
                                213                 :              3 : }
                                214                 :                : 
                                215                 :                : /*
                                216                 :                :  * Inject a member into the archive with specified contents.
                                217                 :                :  */
                                218                 :                : void
  397                           219                 :              3 : astreamer_inject_file(astreamer *streamer, char *pathname, char *data,
                                220                 :                :                       int len)
                                221                 :                : {
                                222                 :                :     astreamer_member member;
                                223                 :                : 
 1401                           224                 :              3 :     strlcpy(member.pathname, pathname, MAXPGPATH);
                                225                 :              3 :     member.size = len;
                                226                 :              3 :     member.mode = pg_file_create_mode;
                                227                 :              3 :     member.is_directory = false;
                                228                 :              3 :     member.is_link = false;
                                229                 :              3 :     member.linktarget[0] = '\0';
                                230                 :                : 
                                231                 :                :     /*
                                232                 :                :      * There seems to be no principled argument for these values, but they are
                                233                 :                :      * what PostgreSQL has historically used.
                                234                 :                :      */
                                235                 :              3 :     member.uid = 04000;
                                236                 :              3 :     member.gid = 02000;
                                237                 :                : 
                                238                 :                :     /*
                                239                 :                :      * We don't know here how to generate valid member headers and trailers
                                240                 :                :      * for the archiving format in use, so if those are needed, some successor
                                241                 :                :      * astreamer will have to generate them using the data from 'member'.
                                242                 :                :      */
  397                           243                 :              3 :     astreamer_content(streamer, &member, NULL, 0,
                                244                 :                :                       ASTREAMER_MEMBER_HEADER);
                                245                 :              3 :     astreamer_content(streamer, &member, data, len,
                                246                 :                :                       ASTREAMER_MEMBER_CONTENTS);
                                247                 :              3 :     astreamer_content(streamer, &member, NULL, 0,
                                248                 :                :                       ASTREAMER_MEMBER_TRAILER);
 1401                           249                 :              3 : }
        

Generated by: LCOV version 2.4-beta