LCOV - differential code coverage report
Current view: top level - src/bin/pg_rewind - file_ops.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 71.4 % 175 125 50 1 124 1
Current Date: 2024-04-14 14:21:10 Functions: 86.7 % 15 13 2 1 12
Baseline: 16@8cea358b128 Branches: 56.5 % 124 70 54 70
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (180,240] days: 100.0 % 1 1 1
(240..) days: 71.3 % 174 124 50 124
Function coverage date bins:
(240..) days: 86.7 % 15 13 2 1 12
Branch coverage date bins:
(240..) days: 56.5 % 124 70 54 70

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * file_ops.c
                                  4                 :                :  *    Helper functions for operating on files.
                                  5                 :                :  *
                                  6                 :                :  * Most of the functions in this file are helper functions for writing to
                                  7                 :                :  * the target data directory. The functions check the --dry-run flag, and
                                  8                 :                :  * do nothing if it's enabled. You should avoid accessing the target files
                                  9                 :                :  * directly but if you do, make sure you honor the --dry-run mode!
                                 10                 :                :  *
                                 11                 :                :  * Portions Copyright (c) 2013-2024, PostgreSQL Global Development Group
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : #include "postgres_fe.h"
                                 16                 :                : 
                                 17                 :                : #include <sys/stat.h>
                                 18                 :                : #include <dirent.h>
                                 19                 :                : #include <fcntl.h>
                                 20                 :                : #include <unistd.h>
                                 21                 :                : 
                                 22                 :                : #include "common/file_perm.h"
                                 23                 :                : #include "common/file_utils.h"
                                 24                 :                : #include "file_ops.h"
                                 25                 :                : #include "filemap.h"
                                 26                 :                : #include "pg_rewind.h"
                                 27                 :                : 
                                 28                 :                : /*
                                 29                 :                :  * Currently open target file.
                                 30                 :                :  */
                                 31                 :                : static int  dstfd = -1;
                                 32                 :                : static char dstpath[MAXPGPATH] = "";
                                 33                 :                : 
                                 34                 :                : static void create_target_dir(const char *path);
                                 35                 :                : static void remove_target_dir(const char *path);
                                 36                 :                : static void create_target_symlink(const char *path, const char *link);
                                 37                 :                : static void remove_target_symlink(const char *path);
                                 38                 :                : 
                                 39                 :                : static void recurse_dir(const char *datadir, const char *parentpath,
                                 40                 :                :                         process_file_callback_t callback);
                                 41                 :                : 
                                 42                 :                : /*
                                 43                 :                :  * Open a target file for writing. If 'trunc' is true and the file already
                                 44                 :                :  * exists, it will be truncated.
                                 45                 :                :  */
                                 46                 :                : void
 3310 heikki.linnakangas@i       47                 :CBC        7456 : open_target_file(const char *path, bool trunc)
                                 48                 :                : {
                                 49                 :                :     int         mode;
                                 50                 :                : 
                                 51         [ +  + ]:           7456 :     if (dry_run)
                                 52                 :            270 :         return;
                                 53                 :                : 
                                 54   [ +  +  +  + ]:           7186 :     if (dstfd != -1 && !trunc &&
                                 55         [ +  + ]:           3252 :         strcmp(path, &dstpath[strlen(datadir_target) + 1]) == 0)
                                 56                 :            899 :         return;                 /* already open */
                                 57                 :                : 
                                 58                 :           6287 :     close_target_file();
                                 59                 :                : 
                                 60                 :           6287 :     snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
                                 61                 :                : 
                                 62                 :           6287 :     mode = O_WRONLY | O_CREAT | PG_BINARY;
                                 63         [ +  + ]:           6287 :     if (trunc)
                                 64                 :           3934 :         mode |= O_TRUNC;
 2199 sfrost@snowman.net         65                 :           6287 :     dstfd = open(dstpath, mode, pg_file_create_mode);
 3310 heikki.linnakangas@i       66         [ -  + ]:           6287 :     if (dstfd < 0)
 1840 peter@eisentraut.org       67                 :UBC           0 :         pg_fatal("could not open target file \"%s\": %m",
                                 68                 :                :                  dstpath);
                                 69                 :                : }
                                 70                 :                : 
                                 71                 :                : /*
                                 72                 :                :  * Close target file, if it's open.
                                 73                 :                :  */
                                 74                 :                : void
 3310 heikki.linnakangas@i       75                 :CBC        6311 : close_target_file(void)
                                 76                 :                : {
                                 77         [ +  + ]:           6311 :     if (dstfd == -1)
                                 78                 :             25 :         return;
                                 79                 :                : 
                                 80         [ -  + ]:           6286 :     if (close(dstfd) != 0)
 1840 peter@eisentraut.org       81                 :UBC           0 :         pg_fatal("could not close target file \"%s\": %m",
                                 82                 :                :                  dstpath);
                                 83                 :                : 
 3310 heikki.linnakangas@i       84                 :CBC        6286 :     dstfd = -1;
                                 85                 :                : }
                                 86                 :                : 
                                 87                 :                : void
                                 88                 :          49133 : write_target_range(char *buf, off_t begin, size_t size)
                                 89                 :                : {
                                 90                 :                :     size_t      writeleft;
                                 91                 :                :     char       *p;
                                 92                 :                : 
                                 93                 :                :     /* update progress report */
                                 94                 :          49133 :     fetch_done += size;
                                 95                 :          49133 :     progress_report(false);
                                 96                 :                : 
                                 97         [ +  + ]:          49133 :     if (dry_run)
                                 98                 :           6731 :         return;
                                 99                 :                : 
                                100         [ -  + ]:          42402 :     if (lseek(dstfd, begin, SEEK_SET) == -1)
 1840 peter@eisentraut.org      101                 :UBC           0 :         pg_fatal("could not seek in target file \"%s\": %m",
                                102                 :                :                  dstpath);
                                103                 :                : 
 3310 heikki.linnakangas@i      104                 :CBC       42402 :     writeleft = size;
                                105                 :          42402 :     p = buf;
                                106         [ +  + ]:          84747 :     while (writeleft > 0)
                                107                 :                :     {
                                108                 :                :         ssize_t     writelen;
                                109                 :                : 
 3230 fujii@postgresql.org      110                 :          42345 :         errno = 0;
 3310 heikki.linnakangas@i      111                 :          42345 :         writelen = write(dstfd, p, writeleft);
                                112         [ -  + ]:          42345 :         if (writelen < 0)
                                113                 :                :         {
                                114                 :                :             /* if write didn't set errno, assume problem is no disk space */
 3230 fujii@postgresql.org      115         [ #  # ]:UBC           0 :             if (errno == 0)
                                116                 :              0 :                 errno = ENOSPC;
 1840 peter@eisentraut.org      117                 :              0 :             pg_fatal("could not write file \"%s\": %m",
                                118                 :                :                      dstpath);
                                119                 :                :         }
                                120                 :                : 
 3310 heikki.linnakangas@i      121                 :CBC       42345 :         p += writelen;
                                122                 :          42345 :         writeleft -= writelen;
                                123                 :                :     }
                                124                 :                : 
                                125                 :                :     /* keep the file open, in case we need to copy more blocks in it */
                                126                 :                : }
                                127                 :                : 
                                128                 :                : 
                                129                 :                : void
                                130                 :            702 : remove_target(file_entry_t *entry)
                                131                 :                : {
                                132         [ -  + ]:            702 :     Assert(entry->action == FILE_ACTION_REMOVE);
 1257                           133         [ -  + ]:            702 :     Assert(entry->target_exists);
                                134                 :                : 
                                135   [ +  +  -  -  :            702 :     switch (entry->target_type)
                                                 - ]
                                136                 :                :     {
 3310                           137                 :             16 :         case FILE_TYPE_DIRECTORY:
                                138                 :             16 :             remove_target_dir(entry->path);
                                139                 :             16 :             break;
                                140                 :                : 
                                141                 :            686 :         case FILE_TYPE_REGULAR:
 2208 fujii@postgresql.org      142                 :            686 :             remove_target_file(entry->path, false);
 3310 heikki.linnakangas@i      143                 :            686 :             break;
                                144                 :                : 
 3310 heikki.linnakangas@i      145                 :UBC           0 :         case FILE_TYPE_SYMLINK:
                                146                 :              0 :             remove_target_symlink(entry->path);
                                147                 :              0 :             break;
                                148                 :                : 
 1257                           149                 :              0 :         case FILE_TYPE_UNDEFINED:
                                150                 :              0 :             pg_fatal("undefined file type for \"%s\"", entry->path);
                                151                 :                :             break;
                                152                 :                :     }
 3310 heikki.linnakangas@i      153                 :CBC         702 : }
                                154                 :                : 
                                155                 :                : void
                                156                 :              9 : create_target(file_entry_t *entry)
                                157                 :                : {
                                158         [ -  + ]:              9 :     Assert(entry->action == FILE_ACTION_CREATE);
 1257                           159         [ -  + ]:              9 :     Assert(!entry->target_exists);
                                160                 :                : 
                                161   [ +  -  -  -  :              9 :     switch (entry->source_type)
                                                 - ]
                                162                 :                :     {
 3310                           163                 :              9 :         case FILE_TYPE_DIRECTORY:
                                164                 :              9 :             create_target_dir(entry->path);
                                165                 :              9 :             break;
                                166                 :                : 
 3310 heikki.linnakangas@i      167                 :UBC           0 :         case FILE_TYPE_SYMLINK:
 1257                           168                 :              0 :             create_target_symlink(entry->path, entry->source_link_target);
 3310                           169                 :              0 :             break;
                                170                 :                : 
                                171                 :              0 :         case FILE_TYPE_REGULAR:
                                172                 :                :             /* can't happen. Regular files are created with open_target_file. */
 1840 peter@eisentraut.org      173                 :              0 :             pg_fatal("invalid action (CREATE) for regular file");
                                174                 :                :             break;
                                175                 :                : 
 1257 heikki.linnakangas@i      176                 :              0 :         case FILE_TYPE_UNDEFINED:
                                177                 :              0 :             pg_fatal("undefined file type for \"%s\"", entry->path);
                                178                 :                :             break;
                                179                 :                :     }
 3310 heikki.linnakangas@i      180                 :CBC           9 : }
                                181                 :                : 
                                182                 :                : /*
                                183                 :                :  * Remove a file from target data directory.  If missing_ok is true, it
                                184                 :                :  * is fine for the target file to not exist.
                                185                 :                :  */
                                186                 :                : void
 2208 fujii@postgresql.org      187                 :            686 : remove_target_file(const char *path, bool missing_ok)
                                188                 :                : {
                                189                 :                :     char        dstpath[MAXPGPATH];
                                190                 :                : 
 3310 heikki.linnakangas@i      191         [ +  + ]:            686 :     if (dry_run)
                                192                 :              7 :         return;
                                193                 :                : 
                                194                 :            679 :     snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
                                195         [ -  + ]:            679 :     if (unlink(dstpath) != 0)
                                196                 :                :     {
 2208 fujii@postgresql.org      197   [ #  #  #  # ]:UBC           0 :         if (errno == ENOENT && missing_ok)
                                198                 :              0 :             return;
                                199                 :                : 
 1840 peter@eisentraut.org      200                 :              0 :         pg_fatal("could not remove file \"%s\": %m",
                                201                 :                :                  dstpath);
                                202                 :                :     }
                                203                 :                : }
                                204                 :                : 
                                205                 :                : void
 3310 heikki.linnakangas@i      206                 :CBC           4 : truncate_target_file(const char *path, off_t newsize)
                                207                 :                : {
                                208                 :                :     char        dstpath[MAXPGPATH];
                                209                 :                :     int         fd;
                                210                 :                : 
                                211         [ +  + ]:              4 :     if (dry_run)
                                212                 :              1 :         return;
                                213                 :                : 
                                214                 :              3 :     snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
                                215                 :                : 
 2199 sfrost@snowman.net        216                 :              3 :     fd = open(dstpath, O_WRONLY, pg_file_create_mode);
 3310 heikki.linnakangas@i      217         [ -  + ]:              3 :     if (fd < 0)
 1840 peter@eisentraut.org      218                 :UBC           0 :         pg_fatal("could not open file \"%s\" for truncation: %m",
                                219                 :                :                  dstpath);
                                220                 :                : 
 3310 heikki.linnakangas@i      221         [ -  + ]:CBC           3 :     if (ftruncate(fd, newsize) != 0)
 1840 peter@eisentraut.org      222                 :UBC           0 :         pg_fatal("could not truncate file \"%s\" to %u: %m",
                                223                 :                :                  dstpath, (unsigned int) newsize);
                                224                 :                : 
 3310 heikki.linnakangas@i      225                 :CBC           3 :     close(fd);
                                226                 :                : }
                                227                 :                : 
                                228                 :                : static void
                                229                 :              9 : create_target_dir(const char *path)
                                230                 :                : {
                                231                 :                :     char        dstpath[MAXPGPATH];
                                232                 :                : 
                                233         [ -  + ]:              9 :     if (dry_run)
 3310 heikki.linnakangas@i      234                 :UBC           0 :         return;
                                235                 :                : 
 3310 heikki.linnakangas@i      236                 :CBC           9 :     snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
 2199 sfrost@snowman.net        237         [ -  + ]:              9 :     if (mkdir(dstpath, pg_dir_create_mode) != 0)
 1840 peter@eisentraut.org      238                 :UBC           0 :         pg_fatal("could not create directory \"%s\": %m",
                                239                 :                :                  dstpath);
                                240                 :                : }
                                241                 :                : 
                                242                 :                : static void
 3310 heikki.linnakangas@i      243                 :CBC          16 : remove_target_dir(const char *path)
                                244                 :                : {
                                245                 :                :     char        dstpath[MAXPGPATH];
                                246                 :                : 
                                247         [ +  + ]:             16 :     if (dry_run)
                                248                 :              1 :         return;
                                249                 :                : 
                                250                 :             15 :     snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
                                251         [ -  + ]:             15 :     if (rmdir(dstpath) != 0)
 1840 peter@eisentraut.org      252                 :UBC           0 :         pg_fatal("could not remove directory \"%s\": %m",
                                253                 :                :                  dstpath);
                                254                 :                : }
                                255                 :                : 
                                256                 :                : static void
 3310 heikki.linnakangas@i      257                 :              0 : create_target_symlink(const char *path, const char *link)
                                258                 :                : {
                                259                 :                :     char        dstpath[MAXPGPATH];
                                260                 :                : 
                                261         [ #  # ]:              0 :     if (dry_run)
                                262                 :              0 :         return;
                                263                 :                : 
                                264                 :              0 :     snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
                                265         [ #  # ]:              0 :     if (symlink(link, dstpath) != 0)
 1840 peter@eisentraut.org      266                 :              0 :         pg_fatal("could not create symbolic link at \"%s\": %m",
                                267                 :                :                  dstpath);
                                268                 :                : }
                                269                 :                : 
                                270                 :                : static void
 3310 heikki.linnakangas@i      271                 :              0 : remove_target_symlink(const char *path)
                                272                 :                : {
                                273                 :                :     char        dstpath[MAXPGPATH];
                                274                 :                : 
                                275         [ #  # ]:              0 :     if (dry_run)
                                276                 :              0 :         return;
                                277                 :                : 
                                278                 :              0 :     snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
                                279         [ #  # ]:              0 :     if (unlink(dstpath) != 0)
 1840 peter@eisentraut.org      280                 :              0 :         pg_fatal("could not remove symbolic link \"%s\": %m",
                                281                 :                :                  dstpath);
                                282                 :                : }
                                283                 :                : 
                                284                 :                : /*
                                285                 :                :  * Sync target data directory to ensure that modifications are safely on disk.
                                286                 :                :  *
                                287                 :                :  * We do this once, for the whole data directory, for performance reasons.  At
                                288                 :                :  * the end of pg_rewind's run, the kernel is likely to already have flushed
                                289                 :                :  * most dirty buffers to disk.  Additionally sync_pgdata uses a two-pass
                                290                 :                :  * approach when fsync is specified (only initiating writeback in the first
                                291                 :                :  * pass), which often reduces the overall amount of IO noticeably.
                                292                 :                :  */
                                293                 :                : void
 1257 heikki.linnakangas@i      294                 :CBC          12 : sync_target_dir(void)
                                295                 :                : {
                                296   [ +  +  -  + ]:             12 :     if (!do_sync || dry_run)
                                297                 :             11 :         return;
                                298                 :                : 
  221 nathan@postgresql.or      299                 :GNC           1 :     sync_pgdata(datadir_target, PG_VERSION_NUM, sync_method);
                                300                 :                : }
                                301                 :                : 
                                302                 :                : 
                                303                 :                : /*
                                304                 :                :  * Read a file into memory. The file to be read is <datadir>/<path>.
                                305                 :                :  * The file contents are returned in a malloc'd buffer, and *filesize
                                306                 :                :  * is set to the length of the file.
                                307                 :                :  *
                                308                 :                :  * The returned buffer is always zero-terminated; the size of the returned
                                309                 :                :  * buffer is actually *filesize + 1. That's handy when reading a text file.
                                310                 :                :  * This function can be used to read binary files as well, you can just
                                311                 :                :  * ignore the zero-terminator in that case.
                                312                 :                :  */
                                313                 :                : char *
 3310 heikki.linnakangas@i      314                 :CBC          51 : slurpFile(const char *datadir, const char *path, size_t *filesize)
                                315                 :                : {
                                316                 :                :     int         fd;
                                317                 :                :     char       *buffer;
                                318                 :                :     struct stat statbuf;
                                319                 :                :     char        fullpath[MAXPGPATH];
                                320                 :                :     int         len;
                                321                 :                :     int         r;
                                322                 :                : 
                                323                 :             51 :     snprintf(fullpath, sizeof(fullpath), "%s/%s", datadir, path);
                                324                 :                : 
                                325         [ -  + ]:             51 :     if ((fd = open(fullpath, O_RDONLY | PG_BINARY, 0)) == -1)
 1840 peter@eisentraut.org      326                 :UBC           0 :         pg_fatal("could not open file \"%s\" for reading: %m",
                                327                 :                :                  fullpath);
                                328                 :                : 
 3310 heikki.linnakangas@i      329         [ -  + ]:CBC          51 :     if (fstat(fd, &statbuf) < 0)
 1840 peter@eisentraut.org      330                 :UBC           0 :         pg_fatal("could not open file \"%s\" for reading: %m",
                                331                 :                :                  fullpath);
                                332                 :                : 
 3310 heikki.linnakangas@i      333                 :CBC          51 :     len = statbuf.st_size;
                                334                 :                : 
                                335                 :             51 :     buffer = pg_malloc(len + 1);
                                336                 :                : 
 2097 michael@paquier.xyz       337                 :             51 :     r = read(fd, buffer, len);
                                338         [ -  + ]:             51 :     if (r != len)
                                339                 :                :     {
 2097 michael@paquier.xyz       340         [ #  # ]:UBC           0 :         if (r < 0)
 1840 peter@eisentraut.org      341                 :              0 :             pg_fatal("could not read file \"%s\": %m",
                                342                 :                :                      fullpath);
                                343                 :                :         else
                                344                 :              0 :             pg_fatal("could not read file \"%s\": read %d of %zu",
                                345                 :                :                      fullpath, r, (Size) len);
                                346                 :                :     }
 3310 heikki.linnakangas@i      347                 :CBC          51 :     close(fd);
                                348                 :                : 
                                349                 :                :     /* Zero-terminate the buffer. */
                                350                 :             51 :     buffer[len] = '\0';
                                351                 :                : 
                                352         [ +  + ]:             51 :     if (filesize)
                                353                 :             42 :         *filesize = len;
                                354                 :             51 :     return buffer;
                                355                 :                : }
                                356                 :                : 
                                357                 :                : /*
                                358                 :                :  * Traverse through all files in a data directory, calling 'callback'
                                359                 :                :  * for each file.
                                360                 :                :  */
                                361                 :                : void
 1257                           362                 :             20 : traverse_datadir(const char *datadir, process_file_callback_t callback)
                                363                 :                : {
                                364                 :             20 :     recurse_dir(datadir, NULL, callback);
                                365                 :             20 : }
                                366                 :                : 
                                367                 :                : /*
                                368                 :                :  * recursive part of traverse_datadir
                                369                 :                :  *
                                370                 :                :  * parentpath is the current subdirectory's path relative to datadir,
                                371                 :                :  * or NULL at the top level.
                                372                 :                :  */
                                373                 :                : static void
                                374                 :            592 : recurse_dir(const char *datadir, const char *parentpath,
                                375                 :                :             process_file_callback_t callback)
                                376                 :                : {
                                377                 :                :     DIR        *xldir;
                                378                 :                :     struct dirent *xlde;
                                379                 :                :     char        fullparentpath[MAXPGPATH];
                                380                 :                : 
                                381         [ +  + ]:            592 :     if (parentpath)
                                382                 :            572 :         snprintf(fullparentpath, MAXPGPATH, "%s/%s", datadir, parentpath);
                                383                 :                :     else
                                384                 :             20 :         snprintf(fullparentpath, MAXPGPATH, "%s", datadir);
                                385                 :                : 
                                386                 :            592 :     xldir = opendir(fullparentpath);
                                387         [ -  + ]:            592 :     if (xldir == NULL)
 1257 heikki.linnakangas@i      388                 :UBC           0 :         pg_fatal("could not open directory \"%s\": %m",
                                389                 :                :                  fullparentpath);
                                390                 :                : 
 1257 heikki.linnakangas@i      391         [ +  + ]:CBC       24680 :     while (errno = 0, (xlde = readdir(xldir)) != NULL)
                                392                 :                :     {
                                393                 :                :         struct stat fst;
                                394                 :                :         char        fullpath[MAXPGPATH * 2];
                                395                 :                :         char        path[MAXPGPATH * 2];
                                396                 :                : 
                                397         [ +  + ]:          24088 :         if (strcmp(xlde->d_name, ".") == 0 ||
                                398         [ +  + ]:          23496 :             strcmp(xlde->d_name, "..") == 0)
                                399                 :           1184 :             continue;
                                400                 :                : 
                                401                 :          22904 :         snprintf(fullpath, sizeof(fullpath), "%s/%s", fullparentpath, xlde->d_name);
                                402                 :                : 
                                403         [ -  + ]:          22904 :         if (lstat(fullpath, &fst) < 0)
                                404                 :                :         {
 1257 heikki.linnakangas@i      405         [ #  # ]:UBC           0 :             if (errno == ENOENT)
                                406                 :                :             {
                                407                 :                :                 /*
                                408                 :                :                  * File doesn't exist anymore. This is ok, if the new primary
                                409                 :                :                  * is running and the file was just removed. If it was a data
                                410                 :                :                  * file, there should be a WAL record of the removal. If it
                                411                 :                :                  * was something else, it couldn't have been anyway.
                                412                 :                :                  *
                                413                 :                :                  * TODO: But complain if we're processing the target dir!
                                414                 :                :                  */
                                415                 :                :             }
                                416                 :                :             else
                                417                 :              0 :                 pg_fatal("could not stat file \"%s\": %m",
                                418                 :                :                          fullpath);
                                419                 :                :         }
                                420                 :                : 
 1257 heikki.linnakangas@i      421         [ +  + ]:CBC       22904 :         if (parentpath)
                                422                 :          22417 :             snprintf(path, sizeof(path), "%s/%s", parentpath, xlde->d_name);
                                423                 :                :         else
                                424                 :            487 :             snprintf(path, sizeof(path), "%s", xlde->d_name);
                                425                 :                : 
                                426         [ +  + ]:          22904 :         if (S_ISREG(fst.st_mode))
                                427                 :          22332 :             callback(path, FILE_TYPE_REGULAR, fst.st_size, NULL);
                                428         [ +  + ]:            572 :         else if (S_ISDIR(fst.st_mode))
                                429                 :                :         {
                                430                 :            570 :             callback(path, FILE_TYPE_DIRECTORY, 0, NULL);
                                431                 :                :             /* recurse to handle subdirectories */
                                432                 :            570 :             recurse_dir(datadir, path, callback);
                                433                 :                :         }
                                434         [ +  - ]:              2 :         else if (S_ISLNK(fst.st_mode))
                                435                 :                :         {
                                436                 :                :             char        link_target[MAXPGPATH];
                                437                 :                :             int         len;
                                438                 :                : 
                                439                 :              2 :             len = readlink(fullpath, link_target, sizeof(link_target));
                                440         [ -  + ]:              2 :             if (len < 0)
 1257 heikki.linnakangas@i      441                 :UBC           0 :                 pg_fatal("could not read symbolic link \"%s\": %m",
                                442                 :                :                          fullpath);
 1257 heikki.linnakangas@i      443         [ -  + ]:CBC           2 :             if (len >= sizeof(link_target))
 1257 heikki.linnakangas@i      444                 :UBC           0 :                 pg_fatal("symbolic link \"%s\" target is too long",
                                445                 :                :                          fullpath);
 1257 heikki.linnakangas@i      446                 :CBC           2 :             link_target[len] = '\0';
                                447                 :                : 
                                448                 :              2 :             callback(path, FILE_TYPE_SYMLINK, 0, link_target);
                                449                 :                : 
                                450                 :                :             /*
                                451                 :                :              * If it's a symlink within pg_tblspc, we need to recurse into it,
                                452                 :                :              * to process all the tablespaces.  We also follow a symlink if
                                453                 :                :              * it's for pg_wal.  Symlinks elsewhere are ignored.
                                454                 :                :              */
                                455   [ -  +  -  - ]:              2 :             if ((parentpath && strcmp(parentpath, "pg_tblspc") == 0) ||
                                456         [ +  - ]:              2 :                 strcmp(path, "pg_wal") == 0)
                                457                 :              2 :                 recurse_dir(datadir, path, callback);
                                458                 :                :         }
                                459                 :                :     }
                                460                 :                : 
                                461         [ -  + ]:            592 :     if (errno)
 1257 heikki.linnakangas@i      462                 :UBC           0 :         pg_fatal("could not read directory \"%s\": %m",
                                463                 :                :                  fullparentpath);
                                464                 :                : 
 1257 heikki.linnakangas@i      465         [ -  + ]:CBC         592 :     if (closedir(xldir))
 1257 heikki.linnakangas@i      466                 :UBC           0 :         pg_fatal("could not close directory \"%s\": %m",
                                467                 :                :                  fullparentpath);
 1257 heikki.linnakangas@i      468                 :CBC         592 : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622