LCOV - differential code coverage report
Current view: top level - src/common - file_utils.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 67.9 % 168 114 50 5 29 9 11 50 33 20 23 55 2 4
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 10 10 8 2 9 1
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 92.3 % 13 12 1 12
Legend: Lines: hit not hit (120,180] days: 67.7 % 31 21 10 21
(240..) days: 65.3 % 124 81 5 29 9 11 50 20 23 55
Function coverage date bins:
[..60] days: 100.0 % 1 1 1
(120,180] days: 100.0 % 1 1 1
(240..) days: 50.0 % 16 8 8 8

 Age         Owner                  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-2023, 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                 : /*
                                 55                 :  * Issue fsync recursively on PGDATA and all its contents.
                                 56                 :  *
                                 57                 :  * We fsync regular files and directories wherever they are, but we follow
                                 58                 :  * symlinks only for pg_wal (or pg_xlog) and immediately under pg_tblspc.
                                 59                 :  * Other symlinks are presumed to point at files we're not responsible for
                                 60                 :  * fsyncing, and might not have privileges to write at all.
                                 61                 :  *
                                 62                 :  * serverVersion indicates the version of the server to be fsync'd.
                                 63                 :  */
                                 64                 : void
 2362 rhaas                      65 GIC           4 : fsync_pgdata(const char *pg_data,
 2362 rhaas                      66 ECB             :              int serverVersion)
                                 67                 : {
                                 68                 :     bool        xlog_is_symlink;
                                 69                 :     char        pg_wal[MAXPGPATH];
                                 70                 :     char        pg_tblspc[MAXPGPATH];
                                 71                 : 
                                 72                 :     /* handle renaming of pg_xlog to pg_wal in post-10 clusters */
 2362 rhaas                      73 GIC           4 :     snprintf(pg_wal, MAXPGPATH, "%s/%s", pg_data,
 2118 tgl                        74 ECB             :              serverVersion < MINIMUM_VERSION_FOR_PG_WAL ? "pg_xlog" : "pg_wal");
 2383 peter_e                    75 GIC           4 :     snprintf(pg_tblspc, MAXPGPATH, "%s/pg_tblspc", pg_data);
 2383 peter_e                    76 ECB             : 
                                 77                 :     /*
                                 78                 :      * If pg_wal is a symlink, we'll need to recurse into it separately,
                                 79                 :      * because the first walkdir below will ignore it.
                                 80                 :      */
 2383 peter_e                    81 GIC           4 :     xlog_is_symlink = false;
 2383 peter_e                    82 ECB             : 
                                 83                 :     {
                                 84                 :         struct stat st;
                                 85                 : 
 2362 rhaas                      86 CBC           4 :         if (lstat(pg_wal, &st) < 0)
 1469 peter                      87 UBC           0 :             pg_log_error("could not stat file \"%s\": %m", pg_wal);
 2383 peter_e                    88 CBC           4 :         else if (S_ISLNK(st.st_mode))
                                 89               1 :             xlog_is_symlink = true;
                                 90                 :     }
                                 91                 : 
                                 92                 :     /*
 2383 peter_e                    93 ECB             :      * If possible, hint to the kernel that we're soon going to fsync the data
                                 94                 :      * directory and its contents.
                                 95                 :      */
                                 96                 : #ifdef PG_FLUSH_DATA_WORKS
 1469 peter                      97 GIC           4 :     walkdir(pg_data, pre_sync_fname, false);
 2383 peter_e                    98               4 :     if (xlog_is_symlink)
 1469 peter                      99               1 :         walkdir(pg_wal, pre_sync_fname, false);
                                100               4 :     walkdir(pg_tblspc, pre_sync_fname, true);
                                101                 : #endif
                                102                 : 
                                103                 :     /*
                                104                 :      * Now we do the fsync()s in the same order.
                                105                 :      *
                                106                 :      * The main call ignores symlinks, so in addition to specially processing
                                107                 :      * pg_wal if it's a symlink, pg_tblspc has to be visited separately with
 2383 peter_e                   108 ECB             :      * process_symlinks = true.  Note that if there are any plain directories
                                109                 :      * in pg_tblspc, they'll get fsync'd twice.  That's not an expected case
                                110                 :      * so we don't worry about optimizing it.
                                111                 :      */
 1469 peter                     112 CBC           4 :     walkdir(pg_data, fsync_fname, false);
 2383 peter_e                   113 GIC           4 :     if (xlog_is_symlink)
 1469 peter                     114               1 :         walkdir(pg_wal, fsync_fname, false);
                                115               4 :     walkdir(pg_tblspc, fsync_fname, true);
 2383 peter_e                   116               4 : }
                                117                 : 
                                118                 : /*
                                119                 :  * Issue fsync recursively on the given directory and all its contents.
 2209 andrew                    120 ECB             :  *
                                121                 :  * This is a convenient wrapper on top of walkdir().
                                122                 :  */
                                123                 : void
 1469 peter                     124 GIC           5 : fsync_dir_recurse(const char *dir)
                                125                 : {
                                126                 :     /*
 2209 andrew                    127 ECB             :      * If possible, hint to the kernel that we're soon going to fsync the data
                                128                 :      * directory and its contents.
                                129                 :      */
                                130                 : #ifdef PG_FLUSH_DATA_WORKS
 1469 peter                     131 CBC           5 :     walkdir(dir, pre_sync_fname, false);
                                132                 : #endif
                                133                 : 
 1469 peter                     134 GIC           5 :     walkdir(dir, fsync_fname, false);
 2209 andrew                    135               5 : }
                                136                 : 
                                137                 : /*
                                138                 :  * walkdir: recursively walk a directory, applying the action to each
                                139                 :  * regular file and directory (including the named directory itself).
                                140                 :  *
                                141                 :  * If process_symlinks is true, the action and recursion are also applied
                                142                 :  * to regular files and directories that are pointed to by symlinks in the
                                143                 :  * given directory; otherwise symlinks are ignored.  Symlinks are always
                                144                 :  * ignored in subdirectories, ie we intentionally don't pass down the
                                145                 :  * process_symlinks flag to recursive calls.
                                146                 :  *
                                147                 :  * Errors are reported but not considered fatal.
 2383 peter_e                   148 ECB             :  *
                                149                 :  * See also walkdir in fd.c, which is a backend version of this logic.
                                150                 :  */
                                151                 : static void
 2383 peter_e                   152 GIC         228 : walkdir(const char *path,
                                153                 :         int (*action) (const char *fname, bool isdir),
                                154                 :         bool process_symlinks)
 2383 peter_e                   155 ECB             : {
                                156                 :     DIR        *dir;
                                157                 :     struct dirent *de;
 2383 peter_e                   158 EUB             : 
 2383 peter_e                   159 GBC         228 :     dir = opendir(path);
 2383 peter_e                   160 GIC         228 :     if (dir == NULL)
                                161                 :     {
 1469 peter                     162 LBC           0 :         pg_log_error("could not open directory \"%s\": %m", path);
 2383 peter_e                   163 UIC           0 :         return;
                                164                 :     }
                                165                 : 
 2383 peter_e                   166 CBC        8960 :     while (errno = 0, (de = readdir(dir)) != NULL)
 2383 peter_e                   167 ECB             :     {
 2189                           168                 :         char        subpath[MAXPGPATH * 2];
                                169                 : 
 2383 peter_e                   170 CBC        8732 :         if (strcmp(de->d_name, ".") == 0 ||
 2383 peter_e                   171 GIC        8504 :             strcmp(de->d_name, "..") == 0)
 2383 peter_e                   172 CBC         456 :             continue;
                                173                 : 
 2189                           174            8276 :         snprintf(subpath, sizeof(subpath), "%s/%s", path, de->d_name);
 2383 peter_e                   175 ECB             : 
  944 tmunro                    176 CBC        8276 :         switch (get_dirent_type(subpath, de, process_symlinks, PG_LOG_ERROR))
 2383 peter_e                   177 ECB             :         {
  944 tmunro                    178 CBC        8074 :             case PGFILETYPE_REG:
                                179            8074 :                 (*action) (subpath, false);
                                180            8074 :                 break;
  944 tmunro                    181 GIC         200 :             case PGFILETYPE_DIR:
                                182             200 :                 walkdir(subpath, action, false);
                                183             200 :                 break;
                                184               2 :             default:
                                185                 : 
                                186                 :                 /*
  944 tmunro                    187 ECB             :                  * Errors are already reported directly by get_dirent_type(),
                                188                 :                  * and any remaining symlinks and unknown file types are
                                189                 :                  * ignored.
                                190                 :                  */
  944 tmunro                    191 CBC           2 :                 break;
 2383 peter_e                   192 EUB             :         }
                                193                 :     }
 2383 peter_e                   194 ECB             : 
 2383 peter_e                   195 GIC         228 :     if (errno)
 1469 peter                     196 UIC           0 :         pg_log_error("could not read directory \"%s\": %m", path);
                                197                 : 
 2383 peter_e                   198 GIC         228 :     (void) closedir(dir);
                                199                 : 
                                200                 :     /*
                                201                 :      * It's important to fsync the destination directory itself as individual
 2383 peter_e                   202 ECB             :      * file fsyncs don't guarantee that the directory entry for the file is
                                203                 :      * synced.  Recent versions of ext4 have made the window much wider but
                                204                 :      * it's been an issue for ext3 and other filesystems in the past.
                                205                 :      */
 1469 peter                     206 GIC         228 :     (*action) (path, true);
                                207                 : }
                                208                 : 
                                209                 : /*
                                210                 :  * Hint to the OS that it should get ready to fsync() this file.
                                211                 :  *
                                212                 :  * Ignores errors trying to open unreadable files, and reports other errors
                                213                 :  * non-fatally.
 2383 peter_e                   214 ECB             :  */
                                215                 : #ifdef PG_FLUSH_DATA_WORKS
                                216                 : 
                                217                 : static int
 1469 peter                     218 CBC        4151 : pre_sync_fname(const char *fname, bool isdir)
                                219                 : {
 2383 peter_e                   220 ECB             :     int         fd;
                                221                 : 
 1668 michael                   222 GBC        4151 :     fd = open(fname, O_RDONLY | PG_BINARY, 0);
 2383 peter_e                   223 EUB             : 
 2383 peter_e                   224 GBC        4151 :     if (fd < 0)
 2383 peter_e                   225 EUB             :     {
 2383 peter_e                   226 UIC           0 :         if (errno == EACCES || (isdir && errno == EISDIR))
                                227               0 :             return 0;
 1469 peter                     228               0 :         pg_log_error("could not open file \"%s\": %m", fname);
 2383 peter_e                   229               0 :         return -1;
                                230                 :     }
                                231                 : 
                                232                 :     /*
                                233                 :      * We do what pg_flush_data() would do in the backend: prefer to use
 2383 peter_e                   234 ECB             :      * sync_file_range, but fall back to posix_fadvise.  We ignore errors
                                235                 :      * because this is only a hint.
                                236                 :      */
                                237                 : #if defined(HAVE_SYNC_FILE_RANGE)
 2383 peter_e                   238 GIC        4151 :     (void) sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE);
                                239                 : #elif defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
                                240                 :     (void) posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
 2383 peter_e                   241 ECB             : #else
                                242                 : #error PG_FLUSH_DATA_WORKS should not have been defined
                                243                 : #endif
                                244                 : 
 2383 peter_e                   245 GIC        4151 :     (void) close(fd);
                                246            4151 :     return 0;
                                247                 : }
                                248                 : 
                                249                 : #endif                          /* PG_FLUSH_DATA_WORKS */
                                250                 : 
                                251                 : /*
                                252                 :  * fsync_fname -- Try to fsync a file or directory
                                253                 :  *
                                254                 :  * Ignores errors trying to open unreadable files, or trying to fsync
 1140 peter                     255 ECB             :  * directories on systems where that isn't allowed/required.  All other errors
                                256                 :  * are fatal.
                                257                 :  */
                                258                 : int
 1469 peter                     259 GIC        4199 : fsync_fname(const char *fname, bool isdir)
                                260                 : {
                                261                 :     int         fd;
                                262                 :     int         flags;
                                263                 :     int         returncode;
                                264                 : 
                                265                 :     /*
                                266                 :      * Some OSs require directories to be opened read-only whereas other
 2383 peter_e                   267 ECB             :      * systems don't allow us to fsync files opened read-only; so we need both
                                268                 :      * cases here.  Using O_RDWR will cause us to fail to fsync files that are
                                269                 :      * not writable by our userid, but we assume that's OK.
                                270                 :      */
 2383 peter_e                   271 CBC        4199 :     flags = PG_BINARY;
 2383 peter_e                   272 GIC        4199 :     if (!isdir)
                                273            4067 :         flags |= O_RDWR;
                                274                 :     else
                                275             132 :         flags |= O_RDONLY;
                                276                 : 
                                277                 :     /*
 2383 peter_e                   278 ECB             :      * Open the file, silently ignoring errors about unreadable files (or
                                279                 :      * unsupported operations, e.g. opening a directory under Windows), and
                                280                 :      * logging others.
 2383 peter_e                   281 EUB             :      */
 1668 michael                   282 GBC        4199 :     fd = open(fname, flags, 0);
 2383 peter_e                   283            4199 :     if (fd < 0)
 2383 peter_e                   284 EUB             :     {
 2383 peter_e                   285 UIC           0 :         if (errno == EACCES || (isdir && errno == EISDIR))
                                286               0 :             return 0;
 1469 peter                     287 LBC           0 :         pg_log_error("could not open file \"%s\": %m", fname);
 2383 peter_e                   288 UIC           0 :         return -1;
                                289                 :     }
                                290                 : 
 2383 peter_e                   291 GIC        4199 :     returncode = fsync(fd);
                                292                 : 
 2383 peter_e                   293 ECB             :     /*
                                294                 :      * Some OSes don't allow us to fsync directories at all, so we can ignore
 2383 peter_e                   295 EUB             :      * those errors. Anything else needs to be reported.
                                296                 :      */
 1505 tmunro                    297 GBC        4199 :     if (returncode != 0 && !(isdir && (errno == EBADF || errno == EINVAL)))
                                298                 :     {
  366 tgl                       299 UIC           0 :         pg_log_error("could not fsync file \"%s\": %m", fname);
 2380 tgl                       300 LBC           0 :         (void) close(fd);
 1140 peter                     301               0 :         exit(EXIT_FAILURE);
                                302                 :     }
                                303                 : 
 2383 peter_e                   304 GIC        4199 :     (void) close(fd);
                                305            4199 :     return 0;
                                306                 : }
                                307                 : 
                                308                 : /*
                                309                 :  * fsync_parent_path -- fsync the parent path of a file or directory
                                310                 :  *
 2383 peter_e                   311 ECB             :  * This is aimed at making file operations persistent on disk in case of
                                312                 :  * an OS crash or power failure.
                                313                 :  */
                                314                 : int
 1469 peter                     315 CBC          14 : fsync_parent_path(const char *fname)
 2383 peter_e                   316 ECB             : {
                                317                 :     char        parentpath[MAXPGPATH];
                                318                 : 
 2383 peter_e                   319 GIC          14 :     strlcpy(parentpath, fname, MAXPGPATH);
                                320              14 :     get_parent_directory(parentpath);
                                321                 : 
                                322                 :     /*
 2383 peter_e                   323 ECB             :      * get_parent_directory() returns an empty string if the input argument is
 2383 peter_e                   324 EUB             :      * just a file name (see comments in path.c), so handle that as being the
                                325                 :      * current directory.
 2383 peter_e                   326 ECB             :      */
 2383 peter_e                   327 GBC          14 :     if (strlen(parentpath) == 0)
 2383 peter_e                   328 UIC           0 :         strlcpy(parentpath, ".", MAXPGPATH);
 2383 peter_e                   329 ECB             : 
 1469 peter                     330 GIC          14 :     if (fsync_fname(parentpath, true) != 0)
 2383 peter_e                   331 UIC           0 :         return -1;
                                332                 : 
 2383 peter_e                   333 GIC          14 :     return 0;
                                334                 : }
                                335                 : 
                                336                 : /*
                                337                 :  * durable_rename -- rename(2) wrapper, issuing fsyncs required for durability
 2383 peter_e                   338 ECB             :  *
                                339                 :  * Wrapper around rename, similar to the backend version.
                                340                 :  */
                                341                 : int
 1469 peter                     342 GIC           3 : durable_rename(const char *oldfile, const char *newfile)
                                343                 : {
                                344                 :     int         fd;
                                345                 : 
                                346                 :     /*
                                347                 :      * First fsync the old and target path (if it exists), to ensure that they
                                348                 :      * are properly persistent on disk. Syncing the target file is not
 2383 peter_e                   349 ECB             :      * strictly necessary, but it makes it easier to reason about crashes;
 2383 peter_e                   350 EUB             :      * because it's then guaranteed that either source or target file exists
                                351                 :      * after a crash.
 2383 peter_e                   352 ECB             :      */
 1469 peter                     353 CBC           3 :     if (fsync_fname(oldfile, false) != 0)
 2383 peter_e                   354 UIC           0 :         return -1;
 2383 peter_e                   355 ECB             : 
 2383 peter_e                   356 GIC           3 :     fd = open(newfile, PG_BINARY | O_RDWR, 0);
 2383 peter_e                   357 GBC           3 :     if (fd < 0)
 2383 peter_e                   358 EUB             :     {
 2383 peter_e                   359 GIC           3 :         if (errno != ENOENT)
                                360                 :         {
 1469 peter                     361 UIC           0 :             pg_log_error("could not open file \"%s\": %m", newfile);
 2383 peter_e                   362               0 :             return -1;
 2383 peter_e                   363 EUB             :         }
                                364                 :     }
                                365                 :     else
                                366                 :     {
 2383 peter_e                   367 UBC           0 :         if (fsync(fd) != 0)
                                368                 :         {
  366 tgl                       369               0 :             pg_log_error("could not fsync file \"%s\": %m", newfile);
 2383 peter_e                   370 UIC           0 :             close(fd);
 1140 peter                     371               0 :             exit(EXIT_FAILURE);
                                372                 :         }
 2383 peter_e                   373 LBC           0 :         close(fd);
                                374                 :     }
 2383 peter_e                   375 EUB             : 
                                376                 :     /* Time to do the real deal... */
 2383 peter_e                   377 GBC           3 :     if (rename(oldfile, newfile) != 0)
                                378                 :     {
 1469 peter                     379 UIC           0 :         pg_log_error("could not rename file \"%s\" to \"%s\": %m",
                                380                 :                      oldfile, newfile);
 2383 peter_e                   381               0 :         return -1;
                                382                 :     }
                                383                 : 
 2383 peter_e                   384 ECB             :     /*
 2383 peter_e                   385 EUB             :      * To guarantee renaming the file is persistent, fsync the file with its
                                386                 :      * new name, and its containing directory.
 2383 peter_e                   387 ECB             :      */
 1469 peter                     388 GBC           3 :     if (fsync_fname(newfile, false) != 0)
 2383 peter_e                   389 UIC           0 :         return -1;
 2383 peter_e                   390 ECB             : 
 1469 peter                     391 GIC           3 :     if (fsync_parent_path(newfile) != 0)
 2383 peter_e                   392 UIC           0 :         return -1;
                                393                 : 
 2383 peter_e                   394 GIC           3 :     return 0;
                                395                 : }
                                396                 : 
                                397                 : #endif                          /* FRONTEND */
                                398                 : 
                                399                 : /*
                                400                 :  * Return the type of a directory entry.
                                401                 :  *
  944 tmunro                    402 ECB             :  * In frontend code, elevel should be a level from logging.h; in backend code
                                403                 :  * it should be a level from elog.h.
                                404                 :  */
                                405                 : PGFileType
  944 tmunro                    406 GIC      321423 : get_dirent_type(const char *path,
                                407                 :                 const struct dirent *de,
                                408                 :                 bool look_through_symlinks,
                                409                 :                 int elevel)
                                410                 : {
                                411                 :     PGFileType  result;
                                412                 : 
                                413                 :     /*
                                414                 :      * Some systems tell us the type directly in the dirent struct, but that's
                                415                 :      * a BSD and Linux extension not required by POSIX.  Even when the
  944 tmunro                    416 ECB             :      * interface is present, sometimes the type is unknown, depending on the
                                417                 :      * filesystem.
                                418                 :      */
                                419                 : #if defined(DT_REG) && defined(DT_DIR) && defined(DT_LNK)
  944 tmunro                    420 CBC      321423 :     if (de->d_type == DT_REG)
                                421          318685 :         result = PGFILETYPE_REG;
  944 tmunro                    422 GIC        2738 :     else if (de->d_type == DT_DIR)
  944 tmunro                    423 GBC        2719 :         result = PGFILETYPE_DIR;
  944 tmunro                    424 GIC          19 :     else if (de->d_type == DT_LNK && !look_through_symlinks)
                                425              19 :         result = PGFILETYPE_LNK;
                                426                 :     else
  944 tmunro                    427 UIC           0 :         result = PGFILETYPE_UNKNOWN;
  944 tmunro                    428 ECB             : #else
                                429                 :     result = PGFILETYPE_UNKNOWN;
                                430                 : #endif
                                431                 : 
  944 tmunro                    432 GIC      321423 :     if (result == PGFILETYPE_UNKNOWN)
                                433                 :     {
  944 tmunro                    434 EUB             :         struct stat fst;
                                435                 :         int         sret;
                                436                 : 
                                437                 : 
  944 tmunro                    438 UIC           0 :         if (look_through_symlinks)
  944 tmunro                    439 UBC           0 :             sret = stat(path, &fst);
                                440                 :         else
                                441               0 :             sret = lstat(path, &fst);
                                442                 : 
                                443               0 :         if (sret < 0)
                                444                 :         {
                                445               0 :             result = PGFILETYPE_ERROR;
                                446                 : #ifdef FRONTEND
  366 tgl                       447 UIC           0 :             pg_log_generic(elevel, PG_LOG_PRIMARY, "could not stat file \"%s\": %m", path);
                                448                 : #else
  944 tmunro                    449               0 :             ereport(elevel,
  944 tmunro                    450 EUB             :                     (errcode_for_file_access(),
                                451                 :                      errmsg("could not stat file \"%s\": %m", path)));
                                452                 : #endif
                                453                 :         }
  944 tmunro                    454 UBC           0 :         else if (S_ISREG(fst.st_mode))
                                455               0 :             result = PGFILETYPE_REG;
  944 tmunro                    456 UIC           0 :         else if (S_ISDIR(fst.st_mode))
                                457               0 :             result = PGFILETYPE_DIR;
                                458               0 :         else if (S_ISLNK(fst.st_mode))
                                459               0 :             result = PGFILETYPE_LNK;
                                460                 :     }
                                461                 : 
  944 tmunro                    462 GIC      321423 :     return result;
                                463                 : }
                                464                 : 
                                465                 : /*
                                466                 :  * pg_pwritev_with_retry
                                467                 :  *
                                468                 :  * Convenience wrapper for pg_pwritev() that retries on partial write.  If an
                                469                 :  * error is returned, it is unspecified how much has been written.
                                470                 :  */
                                471                 : ssize_t
  164 michael                   472 GNC      383622 : pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
                                473                 : {
                                474                 :     struct iovec iov_copy[PG_IOV_MAX];
                                475          383622 :     ssize_t     sum = 0;
                                476                 :     ssize_t     part;
                                477                 : 
                                478                 :     /* We'd better have space to make a copy, in case we need to retry. */
                                479          383622 :     if (iovcnt > PG_IOV_MAX)
                                480                 :     {
  164 michael                   481 UNC           0 :         errno = EINVAL;
                                482               0 :         return -1;
                                483                 :     }
                                484                 : 
                                485                 :     for (;;)
                                486                 :     {
                                487                 :         /* Write as much as we can. */
  164 michael                   488 GNC      383622 :         part = pg_pwritev(fd, iov, iovcnt, offset);
                                489          383622 :         if (part < 0)
  164 michael                   490 UNC           0 :             return -1;
                                491                 : 
                                492                 : #ifdef SIMULATE_SHORT_WRITE
                                493                 :         part = Min(part, 4096);
                                494                 : #endif
                                495                 : 
                                496                 :         /* Count our progress. */
  164 michael                   497 GNC      383622 :         sum += part;
                                498          383622 :         offset += part;
                                499                 : 
                                500                 :         /* Step over iovecs that are done. */
                                501         2014487 :         while (iovcnt > 0 && iov->iov_len <= part)
                                502                 :         {
                                503         1630865 :             part -= iov->iov_len;
                                504         1630865 :             ++iov;
                                505         1630865 :             --iovcnt;
                                506                 :         }
                                507                 : 
                                508                 :         /* Are they all done? */
                                509          383622 :         if (iovcnt == 0)
                                510                 :         {
                                511                 :             /* We don't expect the kernel to write more than requested. */
                                512          383622 :             Assert(part == 0);
                                513          383622 :             break;
                                514                 :         }
                                515                 : 
                                516                 :         /*
                                517                 :          * Move whatever's left to the front of our mutable copy and adjust
                                518                 :          * the leading iovec.
                                519                 :          */
  164 michael                   520 UNC           0 :         Assert(iovcnt > 0);
                                521               0 :         memmove(iov_copy, iov, sizeof(*iov) * iovcnt);
                                522               0 :         Assert(iov->iov_len > part);
                                523               0 :         iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part;
                                524               0 :         iov_copy[0].iov_len -= part;
                                525               0 :         iov = iov_copy;
                                526                 :     }
                                527                 : 
  164 michael                   528 GNC      383622 :     return sum;
                                529                 : }
                                530                 : 
                                531                 : /*
                                532                 :  * pg_pwrite_zeros
                                533                 :  *
                                534                 :  * Writes zeros to file worth "size" bytes at "offset" (from the start of the
                                535                 :  * file), using vectored I/O.
                                536                 :  *
                                537                 :  * Returns the total amount of data written.  On failure, a negative value
                                538                 :  * is returned with errno set.
                                539                 :  */
                                540                 : ssize_t
   34                           541          345216 : pg_pwrite_zeros(int fd, size_t size, off_t offset)
                                542                 : {
                                543                 :     static const PGIOAlignedBlock zbuffer = {{0}};  /* worth BLCKSZ */
    1 tmunro                    544          345216 :     void       *zerobuf_addr = unconstify(PGIOAlignedBlock *, &zbuffer)->data;
                                545                 :     struct iovec iov[PG_IOV_MAX];
   34 michael                   546          345216 :     size_t      remaining_size = size;
  152                           547          345216 :     ssize_t     total_written = 0;
                                548                 : 
                                549                 :     /* Loop, writing as many blocks as we can for each system call. */
   34                           550          728838 :     while (remaining_size > 0)
                                551                 :     {
                                552          383622 :         int         iovcnt = 0;
                                553                 :         ssize_t     written;
                                554                 : 
                                555         2014487 :         for (; iovcnt < PG_IOV_MAX && remaining_size > 0; iovcnt++)
                                556                 :         {
                                557                 :             size_t      this_iov_size;
                                558                 : 
                                559         1630865 :             iov[iovcnt].iov_base = zerobuf_addr;
                                560                 : 
                                561         1630865 :             if (remaining_size < BLCKSZ)
   34 michael                   562 UNC           0 :                 this_iov_size = remaining_size;
                                563                 :             else
   34 michael                   564 GNC     1630865 :                 this_iov_size = BLCKSZ;
                                565                 : 
                                566         1630865 :             iov[iovcnt].iov_len = this_iov_size;
                                567         1630865 :             remaining_size -= this_iov_size;
                                568                 :         }
                                569                 : 
  152                           570          383622 :         written = pg_pwritev_with_retry(fd, iov, iovcnt, offset);
                                571                 : 
                                572          383622 :         if (written < 0)
  152 michael                   573 UNC           0 :             return written;
                                574                 : 
   34 michael                   575 GNC      383622 :         offset += written;
  152                           576          383622 :         total_written += written;
                                577                 :     }
                                578                 : 
                                579          345216 :     Assert(total_written == size);
                                580                 : 
                                581          345216 :     return total_written;
                                582                 : }
        

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