LCOV - differential code coverage report
Current view: top level - src/bin/pg_combinebackup - copy_file.c (source / functions) Coverage Total Hit UNC GNC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 36.6 % 82 30 52 30
Current Date: 2024-04-14 14:21:10 Functions: 40.0 % 5 2 3 2
Baseline: 16@8cea358b128 Branches: 26.7 % 60 16 44 16
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 18.4 % 49 9 40 9
(60,120] days: 63.6 % 33 21 12 21
Function coverage date bins:
[..60] days: 0.0 % 3 0 3
(60,120] days: 100.0 % 2 2 2
Branch coverage date bins:
[..60] days: 12.5 % 32 4 28 4
(60,120] days: 42.9 % 28 12 16 12

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*
                                  2                 :                :  * Copy entire files.
                                  3                 :                :  *
                                  4                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                  5                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  6                 :                :  *
                                  7                 :                :  * src/bin/pg_combinebackup/copy_file.h
                                  8                 :                :  *
                                  9                 :                :  *-------------------------------------------------------------------------
                                 10                 :                :  */
                                 11                 :                : #include "postgres_fe.h"
                                 12                 :                : 
                                 13                 :                : #ifdef HAVE_COPYFILE_H
                                 14                 :                : #include <copyfile.h>
                                 15                 :                : #endif
                                 16                 :                : #include <fcntl.h>
                                 17                 :                : #include <limits.h>
                                 18                 :                : #include <sys/stat.h>
                                 19                 :                : #include <unistd.h>
                                 20                 :                : 
                                 21                 :                : #include "common/file_perm.h"
                                 22                 :                : #include "common/logging.h"
                                 23                 :                : #include "copy_file.h"
                                 24                 :                : 
                                 25                 :                : static void copy_file_blocks(const char *src, const char *dst,
                                 26                 :                :                              pg_checksum_context *checksum_ctx);
                                 27                 :                : 
                                 28                 :                : static void copy_file_clone(const char *src, const char *dst,
                                 29                 :                :                             pg_checksum_context *checksum_ctx);
                                 30                 :                : 
                                 31                 :                : static void copy_file_by_range(const char *src, const char *dst,
                                 32                 :                :                                pg_checksum_context *checksum_ctx);
                                 33                 :                : 
                                 34                 :                : #ifdef WIN32
                                 35                 :                : static void copy_file_copyfile(const char *src, const char *dst,
                                 36                 :                :                                pg_checksum_context *checksum_ctx);
                                 37                 :                : #endif
                                 38                 :                : 
                                 39                 :                : /*
                                 40                 :                :  * Copy a regular file, optionally computing a checksum, and emitting
                                 41                 :                :  * appropriate debug messages. But if we're in dry-run mode, then just emit
                                 42                 :                :  * the messages and don't copy anything.
                                 43                 :                :  */
                                 44                 :                : void
  116 rhaas@postgresql.org       45                 :GNC       10261 : copy_file(const char *src, const char *dst,
                                 46                 :                :           pg_checksum_context *checksum_ctx,
                                 47                 :                :           CopyMethod copy_method, bool dry_run)
                                 48                 :                : {
    9 tomas.vondra@postgre       49                 :          10261 :     char       *strategy_name = NULL;
                                 50                 :          10261 :     void        (*strategy_implementation) (const char *, const char *,
                                 51                 :                :                                             pg_checksum_context *checksum_ctx) = NULL;
                                 52                 :                : 
                                 53                 :                :     /*
                                 54                 :                :      * In dry-run mode, we don't actually copy anything, nor do we read any
                                 55                 :                :      * data from the source file, but we do verify that we can open it.
                                 56                 :                :      */
  116 rhaas@postgresql.org       57         [ -  + ]:          10261 :     if (dry_run)
                                 58                 :                :     {
                                 59                 :                :         int         fd;
                                 60                 :                : 
  116 rhaas@postgresql.org       61         [ #  # ]:UNC           0 :         if ((fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
                                 62                 :              0 :             pg_fatal("could not open \"%s\": %m", src);
                                 63         [ #  # ]:              0 :         if (close(fd) < 0)
                                 64                 :              0 :             pg_fatal("could not close \"%s\": %m", src);
                                 65                 :                :     }
                                 66                 :                : 
                                 67                 :                : #ifdef WIN32
                                 68                 :                :     copy_method = COPY_METHOD_COPYFILE;
                                 69                 :                : #endif
                                 70                 :                : 
                                 71                 :                :     /* Determine the name of the copy strategy for use in log messages. */
    9 tomas.vondra@postgre       72   [ -  +  -  - ]:GNC       10261 :     switch (copy_method)
                                 73                 :                :     {
    9 tomas.vondra@postgre       74                 :UNC           0 :         case COPY_METHOD_CLONE:
                                 75                 :              0 :             strategy_name = "clone";
                                 76                 :              0 :             strategy_implementation = copy_file_clone;
                                 77                 :              0 :             break;
    9 tomas.vondra@postgre       78                 :GNC       10261 :         case COPY_METHOD_COPY:
                                 79                 :                :             /* leave NULL for simple block-by-block copy */
                                 80                 :          10261 :             strategy_implementation = copy_file_blocks;
                                 81                 :          10261 :             break;
    9 tomas.vondra@postgre       82                 :UNC           0 :         case COPY_METHOD_COPY_FILE_RANGE:
                                 83                 :              0 :             strategy_name = "copy_file_range";
                                 84                 :              0 :             strategy_implementation = copy_file_by_range;
                                 85                 :              0 :             break;
                                 86                 :                : #ifdef WIN32
                                 87                 :                :         case COPY_METHOD_COPYFILE:
                                 88                 :                :             strategy_name = "CopyFile";
                                 89                 :                :             strategy_implementation = copy_file_copyfile;
                                 90                 :                :             break;
                                 91                 :                : #endif
                                 92                 :                :     }
                                 93                 :                : 
  116 rhaas@postgresql.org       94         [ -  + ]:GNC       10261 :     if (dry_run)
                                 95                 :                :     {
    9 tomas.vondra@postgre       96         [ #  # ]:UNC           0 :         if (strategy_name)
                                 97         [ #  # ]:              0 :             pg_log_debug("would copy \"%s\" to \"%s\" using strategy %s",
                                 98                 :                :                          src, dst, strategy_name);
                                 99                 :                :         else
  116 rhaas@postgresql.org      100         [ #  # ]:              0 :             pg_log_debug("would copy \"%s\" to \"%s\"",
                                101                 :                :                          src, dst);
                                102                 :                :     }
                                103                 :                :     else
                                104                 :                :     {
    9 tomas.vondra@postgre      105         [ -  + ]:GNC       10261 :         if (strategy_name)
    9 tomas.vondra@postgre      106         [ #  # ]:UNC           0 :             pg_log_debug("copying \"%s\" to \"%s\" using strategy %s",
                                107                 :                :                          src, dst, strategy_name);
    9 tomas.vondra@postgre      108         [ +  + ]:GNC       10261 :         else if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
  116 rhaas@postgresql.org      109         [ +  + ]:           9296 :             pg_log_debug("copying \"%s\" to \"%s\"",
                                110                 :                :                          src, dst);
                                111                 :                :         else
                                112         [ -  + ]:            965 :             pg_log_debug("copying \"%s\" to \"%s\" and checksumming with %s",
                                113                 :                :                          src, dst, pg_checksum_type_name(checksum_ctx->type));
                                114                 :                : 
    9 tomas.vondra@postgre      115                 :          10261 :         strategy_implementation(src, dst, checksum_ctx);
                                116                 :                :     }
  116 rhaas@postgresql.org      117                 :          10261 : }
                                118                 :                : 
                                119                 :                : /*
                                120                 :                :  * Calculate checksum for the src file.
                                121                 :                :  */
                                122                 :                : static void
    9 tomas.vondra@postgre      123                 :UNC           0 : checksum_file(const char *src, pg_checksum_context *checksum_ctx)
                                124                 :                : {
                                125                 :                :     int         src_fd;
                                126                 :                :     uint8      *buffer;
                                127                 :              0 :     const int   buffer_size = 50 * BLCKSZ;
                                128                 :                :     ssize_t     rb;
                                129                 :                : 
                                130                 :                :     /* bail out if no checksum needed */
                                131         [ #  # ]:              0 :     if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
                                132                 :              0 :         return;
                                133                 :                : 
                                134         [ #  # ]:              0 :     if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
                                135                 :              0 :         pg_fatal("could not open file \"%s\": %m", src);
                                136                 :                : 
                                137                 :              0 :     buffer = pg_malloc(buffer_size);
                                138                 :                : 
                                139         [ #  # ]:              0 :     while ((rb = read(src_fd, buffer, buffer_size)) > 0)
                                140                 :                :     {
                                141         [ #  # ]:              0 :         if (pg_checksum_update(checksum_ctx, buffer, rb) < 0)
                                142                 :              0 :             pg_fatal("could not update checksum of file \"%s\"", src);
                                143                 :                :     }
                                144                 :                : 
                                145         [ #  # ]:              0 :     if (rb < 0)
                                146                 :              0 :         pg_fatal("could not read file \"%s\": %m", src);
                                147                 :                : 
                                148                 :              0 :     pg_free(buffer);
                                149                 :              0 :     close(src_fd);
                                150                 :                : }
                                151                 :                : 
                                152                 :                : /*
                                153                 :                :  * Copy a file block by block, and optionally compute a checksum as we go.
                                154                 :                :  */
                                155                 :                : static void
  116 rhaas@postgresql.org      156                 :GNC       10261 : copy_file_blocks(const char *src, const char *dst,
                                157                 :                :                  pg_checksum_context *checksum_ctx)
                                158                 :                : {
                                159                 :                :     int         src_fd;
                                160                 :                :     int         dest_fd;
                                161                 :                :     uint8      *buffer;
                                162                 :          10261 :     const int   buffer_size = 50 * BLCKSZ;
                                163                 :                :     ssize_t     rb;
                                164                 :          10261 :     unsigned    offset = 0;
                                165                 :                : 
                                166         [ -  + ]:          10261 :     if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
  116 rhaas@postgresql.org      167                 :UNC           0 :         pg_fatal("could not open file \"%s\": %m", src);
                                168                 :                : 
  116 rhaas@postgresql.org      169         [ -  + ]:GNC       10261 :     if ((dest_fd = open(dst, O_WRONLY | O_CREAT | O_EXCL | PG_BINARY,
                                170                 :                :                         pg_file_create_mode)) < 0)
  116 rhaas@postgresql.org      171                 :UNC           0 :         pg_fatal("could not open file \"%s\": %m", dst);
                                172                 :                : 
  116 rhaas@postgresql.org      173                 :GNC       10261 :     buffer = pg_malloc(buffer_size);
                                174                 :                : 
                                175         [ +  + ]:          19225 :     while ((rb = read(src_fd, buffer, buffer_size)) > 0)
                                176                 :                :     {
                                177                 :                :         ssize_t     wb;
                                178                 :                : 
                                179         [ -  + ]:           8964 :         if ((wb = write(dest_fd, buffer, rb)) != rb)
                                180                 :                :         {
  116 rhaas@postgresql.org      181         [ #  # ]:UNC           0 :             if (wb < 0)
                                182                 :              0 :                 pg_fatal("could not write file \"%s\": %m", dst);
                                183                 :                :             else
                                184                 :              0 :                 pg_fatal("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
                                185                 :                :                          dst, (int) wb, (int) rb, offset);
                                186                 :                :         }
                                187                 :                : 
  116 rhaas@postgresql.org      188         [ -  + ]:GNC        8964 :         if (pg_checksum_update(checksum_ctx, buffer, rb) < 0)
  116 rhaas@postgresql.org      189                 :UNC           0 :             pg_fatal("could not update checksum of file \"%s\"", dst);
                                190                 :                : 
  116 rhaas@postgresql.org      191                 :GNC        8964 :         offset += rb;
                                192                 :                :     }
                                193                 :                : 
                                194         [ -  + ]:          10261 :     if (rb < 0)
  116 rhaas@postgresql.org      195                 :UNC           0 :         pg_fatal("could not read file \"%s\": %m", dst);
                                196                 :                : 
  116 rhaas@postgresql.org      197                 :GNC       10261 :     pg_free(buffer);
                                198                 :          10261 :     close(src_fd);
                                199                 :          10261 :     close(dest_fd);
                                200                 :          10261 : }
                                201                 :                : 
                                202                 :                : /*
                                203                 :                :  * copy_file_clone
                                204                 :                :  *      Clones/reflinks a file from src to dest.
                                205                 :                :  *
                                206                 :                :  * If needed, also reads the file and calculates the checksum.
                                207                 :                :  */
                                208                 :                : static void
    9 tomas.vondra@postgre      209                 :UNC           0 : copy_file_clone(const char *src, const char *dest,
                                210                 :                :                 pg_checksum_context *checksum_ctx)
                                211                 :                : {
                                212                 :                : #if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
                                213                 :                :     if (copyfile(src, dest, NULL, COPYFILE_CLONE_FORCE) < 0)
                                214                 :                :         pg_fatal("error while cloning file \"%s\" to \"%s\": %m", src, dest);
                                215                 :                : #elif defined(__linux__) && defined(FICLONE)
                                216                 :                :     {
                                217                 :                :         if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
                                218                 :                :             pg_fatal("could not open file \"%s\": %m", src);
                                219                 :                : 
                                220                 :                :         if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
                                221                 :                :                             pg_file_create_mode)) < 0)
                                222                 :                :             pg_fatal("could not create file \"%s\": %m", dest);
                                223                 :                : 
                                224                 :                :         if (ioctl(dest_fd, FICLONE, src_fd) < 0)
                                225                 :                :         {
                                226                 :                :             int         save_errno = errno;
                                227                 :                : 
                                228                 :                :             unlink(dest);
                                229                 :                : 
                                230                 :                :             pg_fatal("error while cloning file \"%s\" to \"%s\": %s",
                                231                 :                :                      src, dest);
                                232                 :                :         }
                                233                 :                :     }
                                234                 :                : #else
                                235                 :              0 :     pg_fatal("file cloning not supported on this platform");
                                236                 :                : #endif
                                237                 :                : 
                                238                 :                :     /* if needed, calculate checksum of the file */
                                239                 :                :     checksum_file(src, checksum_ctx);
                                240                 :                : }
                                241                 :                : 
                                242                 :                : /*
                                243                 :                :  * copy_file_by_range
                                244                 :                :  *      Copies a file from src to dest using copy_file_range system call.
                                245                 :                :  *
                                246                 :                :  * If needed, also reads the file and calculates the checksum.
                                247                 :                :  */
                                248                 :                : static void
                                249                 :              0 : copy_file_by_range(const char *src, const char *dest,
                                250                 :                :                    pg_checksum_context *checksum_ctx)
                                251                 :                : {
                                252                 :                : #if defined(HAVE_COPY_FILE_RANGE)
                                253                 :                :     int         src_fd;
                                254                 :                :     int         dest_fd;
                                255                 :                :     ssize_t     nbytes;
                                256                 :                : 
                                257         [ #  # ]:              0 :     if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
                                258                 :              0 :         pg_fatal("could not open file \"%s\": %m", src);
                                259                 :                : 
                                260         [ #  # ]:              0 :     if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
                                261                 :                :                         pg_file_create_mode)) < 0)
                                262                 :              0 :         pg_fatal("could not create file \"%s\": %m", dest);
                                263                 :                : 
                                264                 :                :     do
                                265                 :                :     {
                                266                 :              0 :         nbytes = copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0);
                                267         [ #  # ]:              0 :         if (nbytes < 0)
                                268                 :              0 :             pg_fatal("error while copying file range from \"%s\" to \"%s\": %m",
                                269                 :                :                      src, dest);
                                270         [ #  # ]:              0 :     } while (nbytes > 0);
                                271                 :                : 
                                272                 :              0 :     close(src_fd);
                                273                 :              0 :     close(dest_fd);
                                274                 :                : #else
                                275                 :                :     pg_fatal("copy_file_range not supported on this platform");
                                276                 :                : #endif
                                277                 :                : 
                                278                 :                :     /* if needed, calculate checksum of the file */
                                279                 :              0 :     checksum_file(src, checksum_ctx);
                                280                 :              0 : }
                                281                 :                : 
                                282                 :                : #ifdef WIN32
                                283                 :                : static void
                                284                 :                : copy_file_copyfile(const char *src, const char *dst,
                                285                 :                :                    pg_checksum_context *checksum_ctx)
                                286                 :                : {
                                287                 :                :     if (CopyFile(src, dst, true) == 0)
                                288                 :                :     {
                                289                 :                :         _dosmaperr(GetLastError());
                                290                 :                :         pg_fatal("could not copy \"%s\" to \"%s\": %m", src, dst);
                                291                 :                :     }
                                292                 :                : 
                                293                 :                :     /* if needed, calculate checksum of the file */
                                294                 :                :     checksum_file(src, checksum_ctx);
                                295                 :                : }
                                296                 :                : #endif                          /* WIN32 */
        

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