LCOV - differential code coverage report
Current view: top level - src/common - file_utils.c (source / functions) Coverage Total Hit UNC UBC GBC GNC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 68.1 % 210 143 19 48 2 47 94 5 19
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 12 12 5 7 2
Baseline: 16@8cea358b128 Branches: 48.9 % 141 69 17 55 23 46
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (120,180] days: 64.7 % 17 11 6 11
(180,240] days: 73.5 % 49 36 13 36
(240..) days: 66.7 % 144 96 48 2 94
Function coverage date bins:
(120,180] days: 100.0 % 1 1 1
(180,240] days: 100.0 % 3 3 3
(240..) days: 100.0 % 8 8 1 7
Branch coverage date bins:
(120,180] days: 42.9 % 14 6 8 6
(180,240] days: 65.4 % 26 17 9 17
(240..) days: 45.5 % 101 46 55 46

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * File-processing utility routines.
                                  4                 :                :  *
                                  5                 :                :  * Assorted utility functions to work on files.
                                  6                 :                :  *
                                  7                 :                :  *
                                  8                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                  9                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 10                 :                :  *
                                 11                 :                :  * src/common/file_utils.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : 
                                 16                 :                : #ifndef FRONTEND
                                 17                 :                : #include "postgres.h"
                                 18                 :                : #else
                                 19                 :                : #include "postgres_fe.h"
                                 20                 :                : #endif
                                 21                 :                : 
                                 22                 :                : #include <dirent.h>
                                 23                 :                : #include <fcntl.h>
                                 24                 :                : #include <sys/stat.h>
                                 25                 :                : #include <unistd.h>
                                 26                 :                : 
                                 27                 :                : #include "common/file_utils.h"
                                 28                 :                : #ifdef FRONTEND
                                 29                 :                : #include "common/logging.h"
                                 30                 :                : #endif
                                 31                 :                : #include "port/pg_iovec.h"
                                 32                 :                : 
                                 33                 :                : #ifdef FRONTEND
                                 34                 :                : 
                                 35                 :                : /* Define PG_FLUSH_DATA_WORKS if we have an implementation for pg_flush_data */
                                 36                 :                : #if defined(HAVE_SYNC_FILE_RANGE)
                                 37                 :                : #define PG_FLUSH_DATA_WORKS 1
                                 38                 :                : #elif defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
                                 39                 :                : #define PG_FLUSH_DATA_WORKS 1
                                 40                 :                : #endif
                                 41                 :                : 
                                 42                 :                : /*
                                 43                 :                :  * pg_xlog has been renamed to pg_wal in version 10.
                                 44                 :                :  */
                                 45                 :                : #define MINIMUM_VERSION_FOR_PG_WAL  100000
                                 46                 :                : 
                                 47                 :                : #ifdef PG_FLUSH_DATA_WORKS
                                 48                 :                : static int  pre_sync_fname(const char *fname, bool isdir);
                                 49                 :                : #endif
                                 50                 :                : static void walkdir(const char *path,
                                 51                 :                :                     int (*action) (const char *fname, bool isdir),
                                 52                 :                :                     bool process_symlinks);
                                 53                 :                : 
                                 54                 :                : #ifdef HAVE_SYNCFS
                                 55                 :                : 
                                 56                 :                : /*
                                 57                 :                :  * do_syncfs -- Try to syncfs a file system
                                 58                 :                :  *
                                 59                 :                :  * Reports errors trying to open the path.  syncfs() errors are fatal.
                                 60                 :                :  */
                                 61                 :                : static void
  221 nathan@postgresql.or       62                 :GNC           2 : do_syncfs(const char *path)
                                 63                 :                : {
                                 64                 :                :     int         fd;
                                 65                 :                : 
                                 66                 :              2 :     fd = open(path, O_RDONLY, 0);
                                 67                 :                : 
                                 68         [ -  + ]:              2 :     if (fd < 0)
                                 69                 :                :     {
  221 nathan@postgresql.or       70                 :UNC           0 :         pg_log_error("could not open file \"%s\": %m", path);
                                 71                 :              0 :         return;
                                 72                 :                :     }
                                 73                 :                : 
  221 nathan@postgresql.or       74         [ -  + ]:GNC           2 :     if (syncfs(fd) < 0)
                                 75                 :                :     {
  221 nathan@postgresql.or       76                 :UNC           0 :         pg_log_error("could not synchronize file system for file \"%s\": %m", path);
                                 77                 :              0 :         (void) close(fd);
                                 78                 :              0 :         exit(EXIT_FAILURE);
                                 79                 :                :     }
                                 80                 :                : 
  221 nathan@postgresql.or       81                 :GNC           2 :     (void) close(fd);
                                 82                 :                : }
                                 83                 :                : 
                                 84                 :                : #endif                          /* HAVE_SYNCFS */
                                 85                 :                : 
                                 86                 :                : /*
                                 87                 :                :  * Synchronize PGDATA and all its contents.
                                 88                 :                :  *
                                 89                 :                :  * We sync regular files and directories wherever they are, but we follow
                                 90                 :                :  * symlinks only for pg_wal (or pg_xlog) and immediately under pg_tblspc.
                                 91                 :                :  * Other symlinks are presumed to point at files we're not responsible for
                                 92                 :                :  * syncing, and might not have privileges to write at all.
                                 93                 :                :  *
                                 94                 :                :  * serverVersion indicates the version of the server to be sync'd.
                                 95                 :                :  */
                                 96                 :                : void
                                 97                 :             13 : sync_pgdata(const char *pg_data,
                                 98                 :                :             int serverVersion,
                                 99                 :                :             DataDirSyncMethod sync_method)
                                100                 :                : {
                                101                 :                :     bool        xlog_is_symlink;
                                102                 :                :     char        pg_wal[MAXPGPATH];
                                103                 :                :     char        pg_tblspc[MAXPGPATH];
                                104                 :                : 
                                105                 :                :     /* handle renaming of pg_xlog to pg_wal in post-10 clusters */
 2733 rhaas@postgresql.org      106         [ -  + ]:CBC          13 :     snprintf(pg_wal, MAXPGPATH, "%s/%s", pg_data,
                                107                 :                :              serverVersion < MINIMUM_VERSION_FOR_PG_WAL ? "pg_xlog" : "pg_wal");
 2754 peter_e@gmx.net           108                 :             13 :     snprintf(pg_tblspc, MAXPGPATH, "%s/pg_tblspc", pg_data);
                                109                 :                : 
                                110                 :                :     /*
                                111                 :                :      * If pg_wal is a symlink, we'll need to recurse into it separately,
                                112                 :                :      * because the first walkdir below will ignore it.
                                113                 :                :      */
                                114                 :             13 :     xlog_is_symlink = false;
                                115                 :                : 
                                116                 :                :     {
                                117                 :                :         struct stat st;
                                118                 :                : 
 2733 rhaas@postgresql.org      119         [ -  + ]:             13 :         if (lstat(pg_wal, &st) < 0)
 1840 peter@eisentraut.org      120                 :UBC           0 :             pg_log_error("could not stat file \"%s\": %m", pg_wal);
 2754 peter_e@gmx.net           121         [ +  + ]:CBC          13 :         else if (S_ISLNK(st.st_mode))
                                122                 :              2 :             xlog_is_symlink = true;
                                123                 :                :     }
                                124                 :                : 
  221 nathan@postgresql.or      125      [ +  +  - ]:GNC          13 :     switch (sync_method)
                                126                 :                :     {
                                127                 :              1 :         case DATA_DIR_SYNC_METHOD_SYNCFS:
                                128                 :                :             {
                                129                 :                : #ifndef HAVE_SYNCFS
                                130                 :                :                 pg_log_error("this build does not support sync method \"%s\"",
                                131                 :                :                              "syncfs");
                                132                 :                :                 exit(EXIT_FAILURE);
                                133                 :                : #else
                                134                 :                :                 DIR        *dir;
                                135                 :                :                 struct dirent *de;
                                136                 :                : 
                                137                 :                :                 /*
                                138                 :                :                  * On Linux, we don't have to open every single file one by
                                139                 :                :                  * one.  We can use syncfs() to sync whole filesystems.  We
                                140                 :                :                  * only expect filesystem boundaries to exist where we
                                141                 :                :                  * tolerate symlinks, namely pg_wal and the tablespaces, so we
                                142                 :                :                  * call syncfs() for each of those directories.
                                143                 :                :                  */
                                144                 :                : 
                                145                 :                :                 /* Sync the top level pgdata directory. */
                                146                 :              1 :                 do_syncfs(pg_data);
                                147                 :                : 
                                148                 :                :                 /* If any tablespaces are configured, sync each of those. */
                                149                 :              1 :                 dir = opendir(pg_tblspc);
                                150         [ -  + ]:              1 :                 if (dir == NULL)
  221 nathan@postgresql.or      151                 :UNC           0 :                     pg_log_error("could not open directory \"%s\": %m",
                                152                 :                :                                  pg_tblspc);
                                153                 :                :                 else
                                154                 :                :                 {
  221 nathan@postgresql.or      155         [ +  + ]:GNC           3 :                     while (errno = 0, (de = readdir(dir)) != NULL)
                                156                 :                :                     {
                                157                 :                :                         char        subpath[MAXPGPATH * 2];
                                158                 :                : 
                                159         [ +  + ]:              2 :                         if (strcmp(de->d_name, ".") == 0 ||
                                160         [ +  - ]:              1 :                             strcmp(de->d_name, "..") == 0)
                                161                 :              2 :                             continue;
                                162                 :                : 
  221 nathan@postgresql.or      163                 :UNC           0 :                         snprintf(subpath, sizeof(subpath), "%s/%s",
                                164                 :              0 :                                  pg_tblspc, de->d_name);
                                165                 :              0 :                         do_syncfs(subpath);
                                166                 :                :                     }
                                167                 :                : 
  221 nathan@postgresql.or      168         [ -  + ]:GNC           1 :                     if (errno)
  221 nathan@postgresql.or      169                 :UNC           0 :                         pg_log_error("could not read directory \"%s\": %m",
                                170                 :                :                                      pg_tblspc);
                                171                 :                : 
  221 nathan@postgresql.or      172                 :GNC           1 :                     (void) closedir(dir);
                                173                 :                :                 }
                                174                 :                : 
                                175                 :                :                 /* If pg_wal is a symlink, process that too. */
                                176         [ +  - ]:              1 :                 if (xlog_is_symlink)
                                177                 :              1 :                     do_syncfs(pg_wal);
                                178                 :                : #endif                          /* HAVE_SYNCFS */
                                179                 :                :             }
                                180                 :              1 :             break;
                                181                 :                : 
                                182                 :             12 :         case DATA_DIR_SYNC_METHOD_FSYNC:
                                183                 :                :             {
                                184                 :                :                 /*
                                185                 :                :                  * If possible, hint to the kernel that we're soon going to
                                186                 :                :                  * fsync the data directory and its contents.
                                187                 :                :                  */
                                188                 :                : #ifdef PG_FLUSH_DATA_WORKS
                                189                 :             12 :                 walkdir(pg_data, pre_sync_fname, false);
                                190         [ +  + ]:             12 :                 if (xlog_is_symlink)
                                191                 :              1 :                     walkdir(pg_wal, pre_sync_fname, false);
                                192                 :             12 :                 walkdir(pg_tblspc, pre_sync_fname, true);
                                193                 :                : #endif
                                194                 :                : 
                                195                 :                :                 /*
                                196                 :                :                  * Now we do the fsync()s in the same order.
                                197                 :                :                  *
                                198                 :                :                  * The main call ignores symlinks, so in addition to specially
                                199                 :                :                  * processing pg_wal if it's a symlink, pg_tblspc has to be
                                200                 :                :                  * visited separately with process_symlinks = true.  Note that
                                201                 :                :                  * if there are any plain directories in pg_tblspc, they'll
                                202                 :                :                  * get fsync'd twice. That's not an expected case so we don't
                                203                 :                :                  * worry about optimizing it.
                                204                 :                :                  */
                                205                 :             12 :                 walkdir(pg_data, fsync_fname, false);
                                206         [ +  + ]:             12 :                 if (xlog_is_symlink)
                                207                 :              1 :                     walkdir(pg_wal, fsync_fname, false);
                                208                 :             12 :                 walkdir(pg_tblspc, fsync_fname, true);
                                209                 :                :             }
                                210                 :             12 :             break;
                                211                 :                :     }
 2754 peter_e@gmx.net           212                 :CBC          13 : }
                                213                 :                : 
                                214                 :                : /*
                                215                 :                :  * Synchronize the given directory and all its contents.
                                216                 :                :  *
                                217                 :                :  * This is a convenient wrapper on top of walkdir() and do_syncfs().
                                218                 :                :  */
                                219                 :                : void
  221 nathan@postgresql.or      220                 :GNC           5 : sync_dir_recurse(const char *dir, DataDirSyncMethod sync_method)
                                221                 :                : {
                                222      [ -  +  - ]:              5 :     switch (sync_method)
                                223                 :                :     {
  221 nathan@postgresql.or      224                 :UNC           0 :         case DATA_DIR_SYNC_METHOD_SYNCFS:
                                225                 :                :             {
                                226                 :                : #ifndef HAVE_SYNCFS
                                227                 :                :                 pg_log_error("this build does not support sync method \"%s\"",
                                228                 :                :                              "syncfs");
                                229                 :                :                 exit(EXIT_FAILURE);
                                230                 :                : #else
                                231                 :                :                 /*
                                232                 :                :                  * On Linux, we don't have to open every single file one by
                                233                 :                :                  * one.  We can use syncfs() to sync the whole filesystem.
                                234                 :                :                  */
                                235                 :              0 :                 do_syncfs(dir);
                                236                 :                : #endif                          /* HAVE_SYNCFS */
                                237                 :                :             }
                                238                 :              0 :             break;
                                239                 :                : 
  221 nathan@postgresql.or      240                 :GNC           5 :         case DATA_DIR_SYNC_METHOD_FSYNC:
                                241                 :                :             {
                                242                 :                :                 /*
                                243                 :                :                  * If possible, hint to the kernel that we're soon going to
                                244                 :                :                  * fsync the data directory and its contents.
                                245                 :                :                  */
                                246                 :                : #ifdef PG_FLUSH_DATA_WORKS
                                247                 :              5 :                 walkdir(dir, pre_sync_fname, false);
                                248                 :                : #endif
                                249                 :                : 
                                250                 :              5 :                 walkdir(dir, fsync_fname, false);
                                251                 :                :             }
                                252                 :              5 :             break;
                                253                 :                :     }
 2580 andrew@dunslane.net       254                 :CBC           5 : }
                                255                 :                : 
                                256                 :                : /*
                                257                 :                :  * walkdir: recursively walk a directory, applying the action to each
                                258                 :                :  * regular file and directory (including the named directory itself).
                                259                 :                :  *
                                260                 :                :  * If process_symlinks is true, the action and recursion are also applied
                                261                 :                :  * to regular files and directories that are pointed to by symlinks in the
                                262                 :                :  * given directory; otherwise symlinks are ignored.  Symlinks are always
                                263                 :                :  * ignored in subdirectories, ie we intentionally don't pass down the
                                264                 :                :  * process_symlinks flag to recursive calls.
                                265                 :                :  *
                                266                 :                :  * Errors are reported but not considered fatal.
                                267                 :                :  *
                                268                 :                :  * See also walkdir in fd.c, which is a backend version of this logic.
                                269                 :                :  */
                                270                 :                : static void
 2754 peter_e@gmx.net           271                 :            688 : walkdir(const char *path,
                                272                 :                :         int (*action) (const char *fname, bool isdir),
                                273                 :                :         bool process_symlinks)
                                274                 :                : {
                                275                 :                :     DIR        *dir;
                                276                 :                :     struct dirent *de;
                                277                 :                : 
                                278                 :            688 :     dir = opendir(path);
                                279         [ -  + ]:            688 :     if (dir == NULL)
                                280                 :                :     {
 1840 peter@eisentraut.org      281                 :UBC           0 :         pg_log_error("could not open directory \"%s\": %m", path);
 2754 peter_e@gmx.net           282                 :              0 :         return;
                                283                 :                :     }
                                284                 :                : 
 2754 peter_e@gmx.net           285         [ +  + ]:CBC       27576 :     while (errno = 0, (de = readdir(dir)) != NULL)
                                286                 :                :     {
                                287                 :                :         char        subpath[MAXPGPATH * 2];
                                288                 :                : 
                                289         [ +  + ]:          26888 :         if (strcmp(de->d_name, ".") == 0 ||
                                290         [ +  + ]:          26200 :             strcmp(de->d_name, "..") == 0)
                                291                 :           1376 :             continue;
                                292                 :                : 
 2560                           293                 :          25512 :         snprintf(subpath, sizeof(subpath), "%s/%s", path, de->d_name);
                                294                 :                : 
 1315 tmunro@postgresql.or      295      [ +  +  + ]:          25512 :         switch (get_dirent_type(subpath, de, process_symlinks, PG_LOG_ERROR))
                                296                 :                :         {
                                297                 :          24882 :             case PGFILETYPE_REG:
                                298                 :          24882 :                 (*action) (subpath, false);
                                299                 :          24882 :                 break;
                                300                 :            628 :             case PGFILETYPE_DIR:
                                301                 :            628 :                 walkdir(subpath, action, false);
                                302                 :            628 :                 break;
                                303                 :              2 :             default:
                                304                 :                : 
                                305                 :                :                 /*
                                306                 :                :                  * Errors are already reported directly by get_dirent_type(),
                                307                 :                :                  * and any remaining symlinks and unknown file types are
                                308                 :                :                  * ignored.
                                309                 :                :                  */
                                310                 :              2 :                 break;
                                311                 :                :         }
                                312                 :                :     }
                                313                 :                : 
 2754 peter_e@gmx.net           314         [ -  + ]:            688 :     if (errno)
 1840 peter@eisentraut.org      315                 :UBC           0 :         pg_log_error("could not read directory \"%s\": %m", path);
                                316                 :                : 
 2754 peter_e@gmx.net           317                 :CBC         688 :     (void) closedir(dir);
                                318                 :                : 
                                319                 :                :     /*
                                320                 :                :      * It's important to fsync the destination directory itself as individual
                                321                 :                :      * file fsyncs don't guarantee that the directory entry for the file is
                                322                 :                :      * synced.  Recent versions of ext4 have made the window much wider but
                                323                 :                :      * it's been an issue for ext3 and other filesystems in the past.
                                324                 :                :      */
 1840 peter@eisentraut.org      325                 :            688 :     (*action) (path, true);
                                326                 :                : }
                                327                 :                : 
                                328                 :                : /*
                                329                 :                :  * Hint to the OS that it should get ready to fsync() this file.
                                330                 :                :  *
                                331                 :                :  * Ignores errors trying to open unreadable files, and reports other errors
                                332                 :                :  * non-fatally.
                                333                 :                :  */
                                334                 :                : #ifdef PG_FLUSH_DATA_WORKS
                                335                 :                : 
                                336                 :                : static int
                                337                 :          12785 : pre_sync_fname(const char *fname, bool isdir)
                                338                 :                : {
                                339                 :                :     int         fd;
                                340                 :                : 
 2039 michael@paquier.xyz       341                 :          12785 :     fd = open(fname, O_RDONLY | PG_BINARY, 0);
                                342                 :                : 
 2754 peter_e@gmx.net           343         [ -  + ]:          12785 :     if (fd < 0)
                                344                 :                :     {
 2754 peter_e@gmx.net           345   [ #  #  #  #  :UBC           0 :         if (errno == EACCES || (isdir && errno == EISDIR))
                                              #  # ]
                                346                 :              0 :             return 0;
 1840 peter@eisentraut.org      347                 :              0 :         pg_log_error("could not open file \"%s\": %m", fname);
 2754 peter_e@gmx.net           348                 :              0 :         return -1;
                                349                 :                :     }
                                350                 :                : 
                                351                 :                :     /*
                                352                 :                :      * We do what pg_flush_data() would do in the backend: prefer to use
                                353                 :                :      * sync_file_range, but fall back to posix_fadvise.  We ignore errors
                                354                 :                :      * because this is only a hint.
                                355                 :                :      */
                                356                 :                : #if defined(HAVE_SYNC_FILE_RANGE)
 2754 peter_e@gmx.net           357                 :CBC       12785 :     (void) sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE);
                                358                 :                : #elif defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
                                359                 :                :     (void) posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
                                360                 :                : #else
                                361                 :                : #error PG_FLUSH_DATA_WORKS should not have been defined
                                362                 :                : #endif
                                363                 :                : 
                                364                 :          12785 :     (void) close(fd);
                                365                 :          12785 :     return 0;
                                366                 :                : }
                                367                 :                : 
                                368                 :                : #endif                          /* PG_FLUSH_DATA_WORKS */
                                369                 :                : 
                                370                 :                : /*
                                371                 :                :  * fsync_fname -- Try to fsync a file or directory
                                372                 :                :  *
                                373                 :                :  * Ignores errors trying to open unreadable files, or trying to fsync
                                374                 :                :  * directories on systems where that isn't allowed/required.  All other errors
                                375                 :                :  * are fatal.
                                376                 :                :  */
                                377                 :                : int
 1840 peter@eisentraut.org      378                 :          12845 : fsync_fname(const char *fname, bool isdir)
                                379                 :                : {
                                380                 :                :     int         fd;
                                381                 :                :     int         flags;
                                382                 :                :     int         returncode;
                                383                 :                : 
                                384                 :                :     /*
                                385                 :                :      * Some OSs require directories to be opened read-only whereas other
                                386                 :                :      * systems don't allow us to fsync files opened read-only; so we need both
                                387                 :                :      * cases here.  Using O_RDWR will cause us to fail to fsync files that are
                                388                 :                :      * not writable by our userid, but we assume that's OK.
                                389                 :                :      */
 2754 peter_e@gmx.net           390                 :          12845 :     flags = PG_BINARY;
                                391         [ +  + ]:          12845 :     if (!isdir)
                                392                 :          12483 :         flags |= O_RDWR;
                                393                 :                :     else
                                394                 :            362 :         flags |= O_RDONLY;
                                395                 :                : 
                                396                 :                :     /*
                                397                 :                :      * Open the file, silently ignoring errors about unreadable files (or
                                398                 :                :      * unsupported operations, e.g. opening a directory under Windows), and
                                399                 :                :      * logging others.
                                400                 :                :      */
 2039 michael@paquier.xyz       401                 :          12845 :     fd = open(fname, flags, 0);
 2754 peter_e@gmx.net           402         [ -  + ]:          12845 :     if (fd < 0)
                                403                 :                :     {
 2754 peter_e@gmx.net           404   [ #  #  #  #  :UBC           0 :         if (errno == EACCES || (isdir && errno == EISDIR))
                                              #  # ]
                                405                 :              0 :             return 0;
 1840 peter@eisentraut.org      406                 :              0 :         pg_log_error("could not open file \"%s\": %m", fname);
 2754 peter_e@gmx.net           407                 :              0 :         return -1;
                                408                 :                :     }
                                409                 :                : 
 2754 peter_e@gmx.net           410                 :CBC       12845 :     returncode = fsync(fd);
                                411                 :                : 
                                412                 :                :     /*
                                413                 :                :      * Some OSes don't allow us to fsync directories at all, so we can ignore
                                414                 :                :      * those errors. Anything else needs to be reported.
                                415                 :                :      */
 1876 tmunro@postgresql.or      416   [ -  +  -  -  :          12845 :     if (returncode != 0 && !(isdir && (errno == EBADF || errno == EINVAL)))
                                        -  -  -  - ]
                                417                 :                :     {
  737 tgl@sss.pgh.pa.us         418                 :UBC           0 :         pg_log_error("could not fsync file \"%s\": %m", fname);
 2751                           419                 :              0 :         (void) close(fd);
 1511 peter@eisentraut.org      420                 :              0 :         exit(EXIT_FAILURE);
                                421                 :                :     }
                                422                 :                : 
 2754 peter_e@gmx.net           423                 :CBC       12845 :     (void) close(fd);
                                424                 :          12845 :     return 0;
                                425                 :                : }
                                426                 :                : 
                                427                 :                : /*
                                428                 :                :  * fsync_parent_path -- fsync the parent path of a file or directory
                                429                 :                :  *
                                430                 :                :  * This is aimed at making file operations persistent on disk in case of
                                431                 :                :  * an OS crash or power failure.
                                432                 :                :  */
                                433                 :                : int
 1840 peter@eisentraut.org      434                 :             14 : fsync_parent_path(const char *fname)
                                435                 :                : {
                                436                 :                :     char        parentpath[MAXPGPATH];
                                437                 :                : 
 2754 peter_e@gmx.net           438                 :             14 :     strlcpy(parentpath, fname, MAXPGPATH);
                                439                 :             14 :     get_parent_directory(parentpath);
                                440                 :                : 
                                441                 :                :     /*
                                442                 :                :      * get_parent_directory() returns an empty string if the input argument is
                                443                 :                :      * just a file name (see comments in path.c), so handle that as being the
                                444                 :                :      * current directory.
                                445                 :                :      */
                                446         [ -  + ]:             14 :     if (strlen(parentpath) == 0)
 2754 peter_e@gmx.net           447                 :UBC           0 :         strlcpy(parentpath, ".", MAXPGPATH);
                                448                 :                : 
 1840 peter@eisentraut.org      449         [ -  + ]:CBC          14 :     if (fsync_fname(parentpath, true) != 0)
 2754 peter_e@gmx.net           450                 :UBC           0 :         return -1;
                                451                 :                : 
 2754 peter_e@gmx.net           452                 :CBC          14 :     return 0;
                                453                 :                : }
                                454                 :                : 
                                455                 :                : /*
                                456                 :                :  * durable_rename -- rename(2) wrapper, issuing fsyncs required for durability
                                457                 :                :  *
                                458                 :                :  * Wrapper around rename, similar to the backend version.
                                459                 :                :  */
                                460                 :                : int
 1840 peter@eisentraut.org      461                 :              3 : durable_rename(const char *oldfile, const char *newfile)
                                462                 :                : {
                                463                 :                :     int         fd;
                                464                 :                : 
                                465                 :                :     /*
                                466                 :                :      * First fsync the old and target path (if it exists), to ensure that they
                                467                 :                :      * are properly persistent on disk. Syncing the target file is not
                                468                 :                :      * strictly necessary, but it makes it easier to reason about crashes;
                                469                 :                :      * because it's then guaranteed that either source or target file exists
                                470                 :                :      * after a crash.
                                471                 :                :      */
                                472         [ -  + ]:              3 :     if (fsync_fname(oldfile, false) != 0)
 2754 peter_e@gmx.net           473                 :UBC           0 :         return -1;
                                474                 :                : 
 2754 peter_e@gmx.net           475                 :CBC           3 :     fd = open(newfile, PG_BINARY | O_RDWR, 0);
                                476         [ +  - ]:              3 :     if (fd < 0)
                                477                 :                :     {
                                478         [ -  + ]:              3 :         if (errno != ENOENT)
                                479                 :                :         {
 1840 peter@eisentraut.org      480                 :UBC           0 :             pg_log_error("could not open file \"%s\": %m", newfile);
 2754 peter_e@gmx.net           481                 :              0 :             return -1;
                                482                 :                :         }
                                483                 :                :     }
                                484                 :                :     else
                                485                 :                :     {
                                486         [ #  # ]:              0 :         if (fsync(fd) != 0)
                                487                 :                :         {
  737 tgl@sss.pgh.pa.us         488                 :              0 :             pg_log_error("could not fsync file \"%s\": %m", newfile);
 2754 peter_e@gmx.net           489                 :              0 :             close(fd);
 1511 peter@eisentraut.org      490                 :              0 :             exit(EXIT_FAILURE);
                                491                 :                :         }
 2754 peter_e@gmx.net           492                 :              0 :         close(fd);
                                493                 :                :     }
                                494                 :                : 
                                495                 :                :     /* Time to do the real deal... */
 2754 peter_e@gmx.net           496         [ -  + ]:CBC           3 :     if (rename(oldfile, newfile) != 0)
                                497                 :                :     {
 1840 peter@eisentraut.org      498                 :UBC           0 :         pg_log_error("could not rename file \"%s\" to \"%s\": %m",
                                499                 :                :                      oldfile, newfile);
 2754 peter_e@gmx.net           500                 :              0 :         return -1;
                                501                 :                :     }
                                502                 :                : 
                                503                 :                :     /*
                                504                 :                :      * To guarantee renaming the file is persistent, fsync the file with its
                                505                 :                :      * new name, and its containing directory.
                                506                 :                :      */
 1840 peter@eisentraut.org      507         [ -  + ]:CBC           3 :     if (fsync_fname(newfile, false) != 0)
 2754 peter_e@gmx.net           508                 :UBC           0 :         return -1;
                                509                 :                : 
 1840 peter@eisentraut.org      510         [ -  + ]:CBC           3 :     if (fsync_parent_path(newfile) != 0)
 2754 peter_e@gmx.net           511                 :UBC           0 :         return -1;
                                512                 :                : 
 2754 peter_e@gmx.net           513                 :CBC           3 :     return 0;
                                514                 :                : }
                                515                 :                : 
                                516                 :                : #endif                          /* FRONTEND */
                                517                 :                : 
                                518                 :                : /*
                                519                 :                :  * Return the type of a directory entry.
                                520                 :                :  *
                                521                 :                :  * In frontend code, elevel should be a level from logging.h; in backend code
                                522                 :                :  * it should be a level from elog.h.
                                523                 :                :  */
                                524                 :                : PGFileType
 1315 tmunro@postgresql.or      525                 :         208715 : get_dirent_type(const char *path,
                                526                 :                :                 const struct dirent *de,
                                527                 :                :                 bool look_through_symlinks,
                                528                 :                :                 int elevel)
                                529                 :                : {
                                530                 :                :     PGFileType  result;
                                531                 :                : 
                                532                 :                :     /*
                                533                 :                :      * Some systems tell us the type directly in the dirent struct, but that's
                                534                 :                :      * a BSD and Linux extension not required by POSIX.  Even when the
                                535                 :                :      * interface is present, sometimes the type is unknown, depending on the
                                536                 :                :      * filesystem.
                                537                 :                :      */
                                538                 :                : #if defined(DT_REG) && defined(DT_DIR) && defined(DT_LNK)
                                539         [ +  + ]:         208715 :     if (de->d_type == DT_REG)
                                540                 :         205066 :         result = PGFILETYPE_REG;
                                541         [ +  + ]:           3649 :     else if (de->d_type == DT_DIR)
                                542                 :           3629 :         result = PGFILETYPE_DIR;
                                543   [ +  -  +  - ]:             20 :     else if (de->d_type == DT_LNK && !look_through_symlinks)
                                544                 :             20 :         result = PGFILETYPE_LNK;
                                545                 :                :     else
 1315 tmunro@postgresql.or      546                 :UBC           0 :         result = PGFILETYPE_UNKNOWN;
                                547                 :                : #else
                                548                 :                :     result = PGFILETYPE_UNKNOWN;
                                549                 :                : #endif
                                550                 :                : 
 1315 tmunro@postgresql.or      551         [ -  + ]:CBC      208715 :     if (result == PGFILETYPE_UNKNOWN)
                                552                 :                :     {
                                553                 :                :         struct stat fst;
                                554                 :                :         int         sret;
                                555                 :                : 
                                556                 :                : 
 1315 tmunro@postgresql.or      557         [ #  # ]:UBC           0 :         if (look_through_symlinks)
                                558                 :              0 :             sret = stat(path, &fst);
                                559                 :                :         else
                                560                 :              0 :             sret = lstat(path, &fst);
                                561                 :                : 
                                562         [ #  # ]:              0 :         if (sret < 0)
                                563                 :                :         {
                                564                 :              0 :             result = PGFILETYPE_ERROR;
                                565                 :                : #ifdef FRONTEND
  737 tgl@sss.pgh.pa.us         566                 :              0 :             pg_log_generic(elevel, PG_LOG_PRIMARY, "could not stat file \"%s\": %m", path);
                                567                 :                : #else
 1315 tmunro@postgresql.or      568         [ #  # ]:              0 :             ereport(elevel,
                                569                 :                :                     (errcode_for_file_access(),
                                570                 :                :                      errmsg("could not stat file \"%s\": %m", path)));
                                571                 :                : #endif
                                572                 :                :         }
                                573         [ #  # ]:              0 :         else if (S_ISREG(fst.st_mode))
                                574                 :              0 :             result = PGFILETYPE_REG;
                                575         [ #  # ]:              0 :         else if (S_ISDIR(fst.st_mode))
                                576                 :              0 :             result = PGFILETYPE_DIR;
                                577         [ #  # ]:              0 :         else if (S_ISLNK(fst.st_mode))
                                578                 :              0 :             result = PGFILETYPE_LNK;
                                579                 :                :     }
                                580                 :                : 
 1315 tmunro@postgresql.or      581                 :CBC      208715 :     return result;
                                582                 :                : }
                                583                 :                : 
                                584                 :                : /*
                                585                 :                :  * Compute what remains to be done after a possibly partial vectored read or
                                586                 :                :  * write.  The part of 'source' beginning after 'transferred' bytes is copied
                                587                 :                :  * to 'destination', and its length is returned.  'source' and 'destination'
                                588                 :                :  * may point to the same array, for in-place adjustment.  A return value of
                                589                 :                :  * zero indicates completion (for callers without a cheaper way to know that).
                                590                 :                :  */
                                591                 :                : int
  124 tmunro@postgresql.or      592                 :GNC      225839 : compute_remaining_iovec(struct iovec *destination,
                                593                 :                :                         const struct iovec *source,
                                594                 :                :                         int iovcnt,
                                595                 :                :                         size_t transferred)
                                596                 :                : {
                                597         [ -  + ]:         225839 :     Assert(iovcnt > 0);
                                598                 :                : 
                                599                 :                :     /* Skip wholly transferred iovecs. */
                                600         [ +  - ]:        1147325 :     while (source->iov_len <= transferred)
                                601                 :                :     {
                                602                 :        1147325 :         transferred -= source->iov_len;
                                603                 :        1147325 :         source++;
                                604                 :        1147325 :         iovcnt--;
                                605                 :                : 
                                606                 :                :         /* All iovecs transferred? */
                                607         [ +  + ]:        1147325 :         if (iovcnt == 0)
                                608                 :                :         {
                                609                 :                :             /*
                                610                 :                :              * We don't expect the kernel to transfer more than we asked it
                                611                 :                :              * to, or something is out of sync.
                                612                 :                :              */
                                613         [ -  + ]:         225839 :             Assert(transferred == 0);
                                614                 :         225839 :             return 0;
                                615                 :                :         }
                                616                 :                :     }
                                617                 :                : 
                                618                 :                :     /* Copy the remaining iovecs to the front of the array. */
  124 tmunro@postgresql.or      619         [ #  # ]:UNC           0 :     if (source != destination)
                                620                 :              0 :         memmove(destination, source, sizeof(*source) * iovcnt);
                                621                 :                : 
                                622                 :                :     /* Adjust leading iovec, which may have been partially transferred. */
                                623         [ #  # ]:              0 :     Assert(destination->iov_len > transferred);
                                624                 :              0 :     destination->iov_base = (char *) destination->iov_base + transferred;
                                625                 :              0 :     destination->iov_len -= transferred;
                                626                 :                : 
                                627                 :              0 :     return iovcnt;
                                628                 :                : }
                                629                 :                : 
                                630                 :                : /*
                                631                 :                :  * pg_pwritev_with_retry
                                632                 :                :  *
                                633                 :                :  * Convenience wrapper for pg_pwritev() that retries on partial write.  If an
                                634                 :                :  * error is returned, it is unspecified how much has been written.
                                635                 :                :  */
                                636                 :                : ssize_t
  535 michael@paquier.xyz       637                 :CBC      225839 : pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
                                638                 :                : {
                                639                 :                :     struct iovec iov_copy[PG_IOV_MAX];
                                640                 :         225839 :     ssize_t     sum = 0;
                                641                 :                :     ssize_t     part;
                                642                 :                : 
                                643                 :                :     /* We'd better have space to make a copy, in case we need to retry. */
                                644         [ -  + ]:         225839 :     if (iovcnt > PG_IOV_MAX)
                                645                 :                :     {
  535 michael@paquier.xyz       646                 :UBC           0 :         errno = EINVAL;
                                647                 :              0 :         return -1;
                                648                 :                :     }
                                649                 :                : 
                                650                 :                :     do
                                651                 :                :     {
                                652                 :                :         /* Write as much as we can. */
  535 michael@paquier.xyz       653                 :GBC      225839 :         part = pg_pwritev(fd, iov, iovcnt, offset);
  535 michael@paquier.xyz       654         [ -  + ]:CBC      225839 :         if (part < 0)
  535 michael@paquier.xyz       655                 :UBC           0 :             return -1;
                                656                 :                : 
                                657                 :                : #ifdef SIMULATE_SHORT_WRITE
                                658                 :                :         part = Min(part, 4096);
                                659                 :                : #endif
                                660                 :                : 
                                661                 :                :         /* Count our progress. */
  535 michael@paquier.xyz       662                 :CBC      225839 :         sum += part;
                                663                 :         225839 :         offset += part;
                                664                 :                : 
                                665                 :                :         /*
                                666                 :                :          * See what is left.  On the first loop we used the caller's array,
                                667                 :                :          * but in later loops we'll use our local copy that we are allowed to
                                668                 :                :          * mutate.
                                669                 :                :          */
  124 tmunro@postgresql.or      670                 :GNC      225839 :         iovcnt = compute_remaining_iovec(iov_copy, iov, iovcnt, part);
  535 michael@paquier.xyz       671                 :GBC      225839 :         iov = iov_copy;
  124 tmunro@postgresql.or      672         [ -  + ]:GNC      225839 :     } while (iovcnt > 0);
                                673                 :                : 
  535 michael@paquier.xyz       674                 :CBC      225839 :     return sum;
                                675                 :                : }
                                676                 :                : 
                                677                 :                : /*
                                678                 :                :  * pg_pwrite_zeros
                                679                 :                :  *
                                680                 :                :  * Writes zeros to file worth "size" bytes at "offset" (from the start of the
                                681                 :                :  * file), using vectored I/O.
                                682                 :                :  *
                                683                 :                :  * Returns the total amount of data written.  On failure, a negative value
                                684                 :                :  * is returned with errno set.
                                685                 :                :  */
                                686                 :                : ssize_t
  405                           687                 :         197003 : pg_pwrite_zeros(int fd, size_t size, off_t offset)
                                688                 :                : {
                                689                 :                :     static const PGIOAlignedBlock zbuffer = {{0}};  /* worth BLCKSZ */
  372 tmunro@postgresql.or      690                 :         197003 :     void       *zerobuf_addr = unconstify(PGIOAlignedBlock *, &zbuffer)->data;
                                691                 :                :     struct iovec iov[PG_IOV_MAX];
  405 michael@paquier.xyz       692                 :         197003 :     size_t      remaining_size = size;
  523                           693                 :         197003 :     ssize_t     total_written = 0;
                                694                 :                : 
                                695                 :                :     /* Loop, writing as many blocks as we can for each system call. */
  405                           696         [ +  + ]:         422842 :     while (remaining_size > 0)
                                697                 :                :     {
                                698                 :         225839 :         int         iovcnt = 0;
                                699                 :                :         ssize_t     written;
                                700                 :                : 
                                701   [ +  +  +  + ]:        1373164 :         for (; iovcnt < PG_IOV_MAX && remaining_size > 0; iovcnt++)
                                702                 :                :         {
                                703                 :                :             size_t      this_iov_size;
                                704                 :                : 
                                705                 :        1147325 :             iov[iovcnt].iov_base = zerobuf_addr;
                                706                 :                : 
                                707         [ -  + ]:        1147325 :             if (remaining_size < BLCKSZ)
  405 michael@paquier.xyz       708                 :UBC           0 :                 this_iov_size = remaining_size;
                                709                 :                :             else
  405 michael@paquier.xyz       710                 :CBC     1147325 :                 this_iov_size = BLCKSZ;
                                711                 :                : 
                                712                 :        1147325 :             iov[iovcnt].iov_len = this_iov_size;
                                713                 :        1147325 :             remaining_size -= this_iov_size;
                                714                 :                :         }
                                715                 :                : 
  523                           716                 :         225839 :         written = pg_pwritev_with_retry(fd, iov, iovcnt, offset);
                                717                 :                : 
                                718         [ -  + ]:         225839 :         if (written < 0)
  523 michael@paquier.xyz       719                 :UBC           0 :             return written;
                                720                 :                : 
  405 michael@paquier.xyz       721                 :CBC      225839 :         offset += written;
  523                           722                 :         225839 :         total_written += written;
                                723                 :                :     }
                                724                 :                : 
                                725         [ -  + ]:         197003 :     Assert(total_written == size);
                                726                 :                : 
                                727                 :         197003 :     return total_written;
                                728                 :                : }
        

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