LCOV - differential code coverage report
Current view: top level - src/bin/pg_upgrade - file.c (source / functions) Coverage Total Hit UBC CBC DUB
Current: 77aeca80249c9e640c811e80633a2e334a9320de vs 38afc3dcb25c45b744d4025029ce0a6c90b7059f Lines: 59.6 % 89 53 36 53 54
Current Date: 2026-07-25 19:08:27 +0900 Functions: 85.7 % 7 6 1 6 1
Baseline: lcov-20260725-baseline Branches: 41.3 % 46 19 27 19
Baseline Date: 2026-07-25 19:09:19 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(360..) days: 59.6 % 89 53 36 53
Function coverage date bins:
(360..) days: 85.7 % 7 6 1 6
Branch coverage date bins:
(360..) days: 41.3 % 46 19 27 19

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*
                                  2                 :                :  *  file.c
                                  3                 :                :  *
                                  4                 :                :  *  file system operations
                                  5                 :                :  *
                                  6                 :                :  *  Copyright (c) 2010-2026, PostgreSQL Global Development Group
                                  7                 :                :  *  src/bin/pg_upgrade/file.c
                                  8                 :                :  */
                                  9                 :                : 
                                 10                 :                : #include "postgres_fe.h"
                                 11                 :                : 
                                 12                 :                : #include <sys/stat.h>
                                 13                 :                : #include <limits.h>
                                 14                 :                : #include <fcntl.h>
                                 15                 :                : #ifdef HAVE_COPYFILE_H
                                 16                 :                : #include <copyfile.h>
                                 17                 :                : #endif
                                 18                 :                : #ifdef __linux__
                                 19                 :                : #include <sys/ioctl.h>
                                 20                 :                : #include <linux/fs.h>
                                 21                 :                : #endif
                                 22                 :                : 
                                 23                 :                : #include "common/file_perm.h"
                                 24                 :                : #include "pg_upgrade.h"
                                 25                 :                : 
                                 26                 :                : 
                                 27                 :                : /*
                                 28                 :                :  * cloneFile()
                                 29                 :                :  *
                                 30                 :                :  * Clones/reflinks a relation file from src to dst.
                                 31                 :                :  *
                                 32                 :                :  * schemaName/relName are relation's SQL name (used for error messages only).
                                 33                 :                :  */
                                 34                 :                : void
 2817 peter_e@gmx.net            35                 :UBC           0 : cloneFile(const char *src, const char *dst,
                                 36                 :                :           const char *schemaName, const char *relName)
                                 37                 :                : {
                                 38                 :                : #if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
                                 39                 :                :     if (copyfile(src, dst, NULL, COPYFILE_CLONE_FORCE) < 0)
                                 40                 :                :         pg_fatal("error while cloning relation \"%s.%s\" (\"%s\" to \"%s\"): %m",
                                 41                 :                :                  schemaName, relName, src, dst);
                                 42                 :                : #elif defined(__linux__) && defined(FICLONE)
                                 43                 :                :     int         src_fd;
                                 44                 :                :     int         dest_fd;
                                 45                 :                : 
                                 46         [ #  # ]:              0 :     if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
  865 michael@paquier.xyz        47                 :              0 :         pg_fatal("error while cloning relation \"%s.%s\": could not open file \"%s\": %m",
                                 48                 :                :                  schemaName, relName, src);
                                 49                 :                : 
 2817 peter_e@gmx.net            50         [ #  # ]:              0 :     if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
                                 51                 :                :                         pg_file_create_mode)) < 0)
  865 michael@paquier.xyz        52                 :              0 :         pg_fatal("error while cloning relation \"%s.%s\": could not create file \"%s\": %m",
                                 53                 :                :                  schemaName, relName, dst);
                                 54                 :                : 
 2817 peter_e@gmx.net            55         [ #  # ]:              0 :     if (ioctl(dest_fd, FICLONE, src_fd) < 0)
                                 56                 :                :     {
 1454 michael@paquier.xyz        57                 :              0 :         int         save_errno = errno;
                                 58                 :                : 
 2817 peter_e@gmx.net            59                 :              0 :         unlink(dst);
                                 60                 :                : 
 1474 tgl@sss.pgh.pa.us          61                 :              0 :         pg_fatal("error while cloning relation \"%s.%s\" (\"%s\" to \"%s\"): %s",
                                 62                 :                :                  schemaName, relName, src, dst, strerror(save_errno));
                                 63                 :                :     }
                                 64                 :                : 
 2817 peter_e@gmx.net            65                 :              0 :     close(src_fd);
                                 66                 :              0 :     close(dest_fd);
                                 67                 :                : #endif
                                 68                 :              0 : }
                                 69                 :                : 
                                 70                 :                : 
                                 71                 :                : /*
                                 72                 :                :  * copyFile()
                                 73                 :                :  *
                                 74                 :                :  * Copies a relation file from src to dst.
                                 75                 :                :  * schemaName/relName are relation's SQL name (used for error messages only).
                                 76                 :                :  */
                                 77                 :                : void
 3585 tgl@sss.pgh.pa.us          78                 :CBC        2020 : copyFile(const char *src, const char *dst,
                                 79                 :                :          const char *schemaName, const char *relName)
                                 80                 :                : {
                                 81                 :                : #ifndef WIN32
                                 82                 :                :     int         src_fd;
                                 83                 :                :     int         dest_fd;
                                 84                 :                :     char       *buffer;
                                 85                 :                : 
                                 86         [ -  + ]:           2020 :     if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
  865 michael@paquier.xyz        87                 :UBC           0 :         pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %m",
                                 88                 :                :                  schemaName, relName, src);
                                 89                 :                : 
 3585 tgl@sss.pgh.pa.us          90         [ -  + ]:CBC        2020 :     if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
                                 91                 :                :                         pg_file_create_mode)) < 0)
  865 michael@paquier.xyz        92                 :UBC           0 :         pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %m",
                                 93                 :                :                  schemaName, relName, dst);
                                 94                 :                : 
                                 95                 :                :     /* copy in fairly large chunks for best efficiency */
                                 96                 :                : #define COPY_BUF_SIZE (50 * BLCKSZ)
                                 97                 :                : 
 4991 bruce@momjian.us           98                 :CBC        2020 :     buffer = (char *) pg_malloc(COPY_BUF_SIZE);
                                 99                 :                : 
                                100                 :                :     /* perform data copying i.e read src source, write to destination */
                                101                 :                :     while (true)
 5918                           102                 :           1586 :     {
                                103                 :           3606 :         ssize_t     nbytes = read(src_fd, buffer, COPY_BUF_SIZE);
                                104                 :                : 
                                105         [ -  + ]:           3606 :         if (nbytes < 0)
  865 michael@paquier.xyz       106                 :UBC           0 :             pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %m",
                                107                 :                :                      schemaName, relName, src);
                                108                 :                : 
 5918 bruce@momjian.us          109         [ +  + ]:CBC        3606 :         if (nbytes == 0)
                                110                 :           2020 :             break;
                                111                 :                : 
                                112                 :           1586 :         errno = 0;
                                113         [ -  + ]:           1586 :         if (write(dest_fd, buffer, nbytes) != nbytes)
                                114                 :                :         {
                                115                 :                :             /* if write didn't set errno, assume problem is no disk space */
 4632 peter_e@gmx.net           116         [ #  # ]:UBC           0 :             if (errno == 0)
                                117                 :              0 :                 errno = ENOSPC;
  865 michael@paquier.xyz       118                 :              0 :             pg_fatal("error while copying relation \"%s.%s\": could not write file \"%s\": %m",
                                119                 :                :                      schemaName, relName, dst);
                                120                 :                :         }
                                121                 :                :     }
                                122                 :                : 
 4991 bruce@momjian.us          123                 :CBC        2020 :     pg_free(buffer);
 3585 tgl@sss.pgh.pa.us         124                 :           2020 :     close(src_fd);
                                125                 :           2020 :     close(dest_fd);
                                126                 :                : 
                                127                 :                : #else                           /* WIN32 */
                                128                 :                : 
                                129                 :                :     if (CopyFile(src, dst, true) == 0)
                                130                 :                :     {
                                131                 :                :         _dosmaperr(GetLastError());
                                132                 :                :         pg_fatal("error while copying relation \"%s.%s\" (\"%s\" to \"%s\"): %m",
                                133                 :                :                  schemaName, relName, src, dst);
                                134                 :                :     }
                                135                 :                : 
                                136                 :                : #endif                          /* WIN32 */
                                137                 :           2020 : }
                                138                 :                : 
                                139                 :                : 
                                140                 :                : /*
                                141                 :                :  * copyFileByRange()
                                142                 :                :  *
                                143                 :                :  * Copies a relation file from src to dst.
                                144                 :                :  * schemaName/relName are relation's SQL name (used for error messages only).
                                145                 :                :  */
                                146                 :                : void
  871 tmunro@postgresql.or      147                 :             20 : copyFileByRange(const char *src, const char *dst,
                                148                 :                :                 const char *schemaName, const char *relName)
                                149                 :                : {
                                150                 :                : #ifdef HAVE_COPY_FILE_RANGE
                                151                 :                :     int         src_fd;
                                152                 :                :     int         dest_fd;
                                153                 :                :     ssize_t     nbytes;
                                154                 :                : 
                                155         [ -  + ]:             20 :     if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
  865 michael@paquier.xyz       156                 :UBC           0 :         pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %m",
                                157                 :                :                  schemaName, relName, src);
                                158                 :                : 
  871 tmunro@postgresql.or      159         [ -  + ]:CBC          20 :     if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
                                160                 :                :                         pg_file_create_mode)) < 0)
  865 michael@paquier.xyz       161                 :UBC           0 :         pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %m",
                                162                 :                :                  schemaName, relName, dst);
                                163                 :                : 
                                164                 :                :     do
                                165                 :                :     {
  871 tmunro@postgresql.or      166                 :CBC          34 :         nbytes = copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0);
                                167         [ -  + ]:             34 :         if (nbytes < 0)
  865 michael@paquier.xyz       168                 :UBC           0 :             pg_fatal("error while copying relation \"%s.%s\": could not copy file range from \"%s\" to \"%s\": %m",
                                169                 :                :                      schemaName, relName, src, dst);
                                170                 :                :     }
  871 tmunro@postgresql.or      171         [ +  + ]:CBC          34 :     while (nbytes > 0);
                                172                 :                : 
                                173                 :             20 :     close(src_fd);
                                174                 :             20 :     close(dest_fd);
                                175                 :                : #endif
                                176                 :             20 : }
                                177                 :                : 
                                178                 :                : 
                                179                 :                : /*
                                180                 :                :  * linkFile()
                                181                 :                :  *
                                182                 :                :  * Hard-links a relation file from src to dst.
                                183                 :                :  * schemaName/relName are relation's SQL name (used for error messages only).
                                184                 :                :  */
                                185                 :                : void
 3585 tgl@sss.pgh.pa.us         186                 :             20 : linkFile(const char *src, const char *dst,
                                187                 :                :          const char *schemaName, const char *relName)
                                188                 :                : {
 2334 peter@eisentraut.org      189         [ -  + ]:             20 :     if (link(src, dst) < 0)
  865 michael@paquier.xyz       190                 :UBC           0 :         pg_fatal("error while creating link for relation \"%s.%s\" (\"%s\" to \"%s\"): %m",
                                191                 :                :                  schemaName, relName, src, dst);
 5918 bruce@momjian.us          192                 :CBC          20 : }
                                193                 :                : 
                                194                 :                : 
                                195                 :                : void
 2817 peter_e@gmx.net           196                 :              1 : check_file_clone(void)
                                197                 :                : {
                                198                 :                :     char        existing_file[MAXPGPATH];
                                199                 :                :     char        new_link_file[MAXPGPATH];
                                200                 :                : 
                                201                 :              1 :     snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata);
                                202                 :              1 :     snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.clonetest", new_cluster.pgdata);
                                203                 :              1 :     unlink(new_link_file);      /* might fail */
                                204                 :                : 
                                205                 :                : #if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
                                206                 :                :     if (copyfile(existing_file, new_link_file, NULL, COPYFILE_CLONE_FORCE) < 0)
                                207                 :                :         pg_fatal("could not clone file between old and new data directories: %m");
                                208                 :                : #elif defined(__linux__) && defined(FICLONE)
                                209                 :                :     {
                                210                 :                :         int         src_fd;
                                211                 :                :         int         dest_fd;
                                212                 :                : 
                                213         [ -  + ]:              1 :         if ((src_fd = open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0)
  865 michael@paquier.xyz       214                 :UBC           0 :             pg_fatal("could not open file \"%s\": %m",
                                215                 :                :                      existing_file);
                                216                 :                : 
 2817 peter_e@gmx.net           217         [ -  + ]:CBC           1 :         if ((dest_fd = open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
                                218                 :                :                             pg_file_create_mode)) < 0)
  865 michael@paquier.xyz       219                 :UBC           0 :             pg_fatal("could not create file \"%s\": %m",
                                220                 :                :                      new_link_file);
                                221                 :                : 
 2817 peter_e@gmx.net           222         [ +  - ]:CBC           1 :         if (ioctl(dest_fd, FICLONE, src_fd) < 0)
  865 michael@paquier.xyz       223                 :              1 :             pg_fatal("could not clone file between old and new data directories: %m");
                                224                 :                : 
 2817 peter_e@gmx.net           225                 :UBC           0 :         close(src_fd);
                                226                 :              0 :         close(dest_fd);
                                227                 :                :     }
                                228                 :                : #else
                                229                 :                :     pg_fatal("file cloning not supported on this platform");
                                230                 :                : #endif
                                231                 :                : 
                                232                 :              0 :     unlink(new_link_file);
                                233                 :              0 : }
                                234                 :                : 
                                235                 :                : void
  871 tmunro@postgresql.or      236                 :CBC           1 : check_copy_file_range(void)
                                237                 :                : {
                                238                 :                :     char        existing_file[MAXPGPATH];
                                239                 :                :     char        new_link_file[MAXPGPATH];
                                240                 :                : 
                                241                 :              1 :     snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata);
                                242                 :              1 :     snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.copy_file_range_test", new_cluster.pgdata);
                                243                 :              1 :     unlink(new_link_file);      /* might fail */
                                244                 :                : 
                                245                 :                : #if defined(HAVE_COPY_FILE_RANGE)
                                246                 :                :     {
                                247                 :                :         int         src_fd;
                                248                 :                :         int         dest_fd;
                                249                 :                : 
                                250         [ -  + ]:              1 :         if ((src_fd = open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0)
  865 michael@paquier.xyz       251                 :UBC           0 :             pg_fatal("could not open file \"%s\": %m",
                                252                 :                :                      existing_file);
                                253                 :                : 
  871 tmunro@postgresql.or      254         [ -  + ]:CBC           1 :         if ((dest_fd = open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
                                255                 :                :                             pg_file_create_mode)) < 0)
  865 michael@paquier.xyz       256                 :UBC           0 :             pg_fatal("could not create file \"%s\": %m",
                                257                 :                :                      new_link_file);
                                258                 :                : 
  871 tmunro@postgresql.or      259         [ -  + ]:CBC           1 :         if (copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0) < 0)
  865 michael@paquier.xyz       260                 :UBC           0 :             pg_fatal("could not copy file range between old and new data directories: %m");
                                261                 :                : 
  871 tmunro@postgresql.or      262                 :CBC           1 :         close(src_fd);
                                263                 :              1 :         close(dest_fd);
                                264                 :                :     }
                                265                 :                : #else
                                266                 :                :     pg_fatal("copy_file_range not supported on this platform");
                                267                 :                : #endif
                                268                 :                : 
                                269                 :              1 :     unlink(new_link_file);
                                270                 :              1 : }
                                271                 :                : 
                                272                 :                : void
  487 nathan@postgresql.or      273                 :              2 : check_hard_link(transferMode transfer_mode)
                                274                 :                : {
                                275                 :                :     char        existing_file[MAXPGPATH];
                                276                 :                :     char        new_link_file[MAXPGPATH];
                                277                 :                : 
 5758 bruce@momjian.us          278                 :              2 :     snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata);
                                279                 :              2 :     snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.linktest", new_cluster.pgdata);
 5918                           280                 :              2 :     unlink(new_link_file);      /* might fail */
                                281                 :                : 
 2334 peter@eisentraut.org      282         [ -  + ]:              2 :     if (link(existing_file, new_link_file) < 0)
                                283                 :                :     {
  487 nathan@postgresql.or      284         [ #  # ]:UBC           0 :         if (transfer_mode == TRANSFER_MODE_LINK)
                                285                 :              0 :             pg_fatal("could not create hard link between old and new data directories: %m\n"
                                286                 :                :                      "In link mode the old and new data directories must be on the same file system.");
                                287         [ #  # ]:              0 :         else if (transfer_mode == TRANSFER_MODE_SWAP)
                                288                 :              0 :             pg_fatal("could not create hard link between old and new data directories: %m\n"
                                289                 :                :                      "In swap mode the old and new data directories must be on the same file system.");
                                290                 :                :         else
                                291                 :              0 :             pg_fatal("unrecognized transfer mode");
                                292                 :                :     }
                                293                 :                : 
 5918 bruce@momjian.us          294                 :CBC           2 :     unlink(new_link_file);
                                295                 :              2 : }
        

Generated by: LCOV version 2.0-1