LCOV - differential code coverage report
Current view: top level - src/backend/storage/file - copydir.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: 68.2 % 66 45 1 5 11 4 2 21 5 17 13 19 2 4
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 2 2 2 1 1
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 2 2 2
Legend: Lines: hit not hit (180,240] days: 75.0 % 4 3 1 3
(240..) days: 66.7 % 60 40 5 11 4 2 21 17 13 19
Function coverage date bins:
(60,120] days: 100.0 % 2 2 2
(240..) days: 0.0 % 1 0 1

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * copydir.c
                                  4                 :  *    copies a directory
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  7                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :  *
                                  9                 :  *  While "xcopy /e /i /q" works fine for copying directories, on Windows XP
                                 10                 :  *  it requires a Window handle which prevents it from working when invoked
                                 11                 :  *  as a service.
                                 12                 :  *
                                 13                 :  * IDENTIFICATION
                                 14                 :  *    src/backend/storage/file/copydir.c
                                 15                 :  *
                                 16                 :  *-------------------------------------------------------------------------
                                 17                 :  */
                                 18                 : 
                                 19                 : #include "postgres.h"
                                 20                 : 
                                 21                 : #include <fcntl.h>
                                 22                 : #include <unistd.h>
                                 23                 : 
                                 24                 : #include "common/file_utils.h"
                                 25                 : #include "miscadmin.h"
                                 26                 : #include "pgstat.h"
                                 27                 : #include "storage/copydir.h"
                                 28                 : #include "storage/fd.h"
                                 29                 : 
                                 30                 : /*
                                 31                 :  * copydir: copy a directory
                                 32                 :  *
                                 33                 :  * If recurse is false, subdirectories are ignored.  Anything that's not
                                 34                 :  * a directory or a regular file is ignored.
                                 35                 :  */
                                 36                 : void
   81 michael                    37 GNC         621 : copydir(const char *fromdir, const char *todir, bool recurse)
                                 38                 : {
                                 39                 :     DIR        *xldir;
                                 40                 :     struct dirent *xlde;
                                 41                 :     char        fromfile[MAXPGPATH * 2];
                                 42                 :     char        tofile[MAXPGPATH * 2];
                                 43                 : 
 1828 sfrost                     44 CBC         621 :     if (MakePGDirectory(todir) != 0)
 6459 tgl                        45 UBC           0 :         ereport(ERROR,
                                 46                 :                 (errcode_for_file_access(),
                                 47                 :                  errmsg("could not create directory \"%s\": %m", todir)));
                                 48                 : 
 6985 tgl                        49 CBC         621 :     xldir = AllocateDir(fromdir);
                                 50                 : 
 6459                            51          186965 :     while ((xlde = ReadDir(xldir, fromdir)) != NULL)
                                 52                 :     {
                                 53                 :         PGFileType  xlde_type;
                                 54                 : 
                                 55                 :         /* If we got a cancel signal during the copy of the directory, quit */
 4660 bruce                      56          186344 :         CHECK_FOR_INTERRUPTS();
                                 57                 : 
 6385                            58          186344 :         if (strcmp(xlde->d_name, ".") == 0 ||
 6459 tgl                        59          185723 :             strcmp(xlde->d_name, "..") == 0)
 6385 bruce                      60            1242 :             continue;
                                 61                 : 
 2189 peter_e                    62          185102 :         snprintf(fromfile, sizeof(fromfile), "%s/%s", fromdir, xlde->d_name);
                                 63          185102 :         snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
                                 64                 : 
  219 michael                    65 GNC      185102 :         xlde_type = get_dirent_type(fromfile, xlde, false, ERROR);
                                 66                 : 
                                 67          185102 :         if (xlde_type == PGFILETYPE_DIR)
 6459 tgl                        68 EUB             :         {
                                 69                 :             /* recurse to handle subdirectories */
 6459 tgl                        70 LBC           0 :             if (recurse)
                                 71               0 :                 copydir(fromfile, tofile, true);
                                 72                 :         }
  219 michael                    73 GNC      185102 :         else if (xlde_type == PGFILETYPE_REG)
 6459 tgl                        74 GIC      185102 :             copy_file(fromfile, tofile);
                                 75                 :     }
 4794                            76             621 :     FreeDir(xldir);
                                 77                 : 
                                 78                 :     /*
 4794 tgl                        79 ECB             :      * Be paranoid here and fsync all files to ensure the copy is really done.
 3914                            80                 :      * But if fsync is disabled, we're done.
                                 81                 :      */
 3914 tgl                        82 GBC         621 :     if (!enableFsync)
 3914 tgl                        83 GIC         621 :         return;
 3914 tgl                        84 EUB             : 
 4794 tgl                        85 UIC           0 :     xldir = AllocateDir(todir);
 4801 stark                      86 EUB             : 
 4794 tgl                        87 UBC           0 :     while ((xlde = ReadDir(xldir, todir)) != NULL)
 4801 stark                      88 EUB             :     {
 4801 stark                      89 UIC           0 :         if (strcmp(xlde->d_name, ".") == 0 ||
                                 90               0 :             strcmp(xlde->d_name, "..") == 0)
                                 91               0 :             continue;
                                 92                 : 
 2189 peter_e                    93               0 :         snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
 4801 stark                      94 EUB             : 
 4794 tgl                        95                 :         /*
                                 96                 :          * We don't need to sync subdirectories here since the recursive
                                 97                 :          * copydir will do it before it returns
                                 98                 :          */
  219 michael                    99 UNC           0 :         if (get_dirent_type(tofile, xlde, false, ERROR) == PGFILETYPE_REG)
 4788 stark                     100 UBC           0 :             fsync_fname(tofile, false);
                                101                 :     }
 4801 stark                     102 UIC           0 :     FreeDir(xldir);
                                103                 : 
                                104                 :     /*
                                105                 :      * It's important to fsync the destination directory itself as individual
                                106                 :      * file fsyncs don't guarantee that the directory entry for the file is
 4790 bruce                     107 ECB             :      * synced. Recent versions of ext4 have made the window much wider but
                                108                 :      * it's been true for ext3 and other filesystems in the past.
                                109                 :      */
 4788 stark                     110 UIC           0 :     fsync_fname(todir, true);
                                111                 : }
                                112                 : 
                                113                 : /*
                                114                 :  * copy one file
                                115                 :  */
                                116                 : void
   81 michael                   117 GNC      185111 : copy_file(const char *fromfile, const char *tofile)
                                118                 : {
                                119                 :     char       *buffer;
                                120                 :     int         srcfd;
                                121                 :     int         dstfd;
                                122                 :     int         nbytes;
                                123                 :     off_t       offset;
                                124                 :     off_t       flush_offset;
                                125                 : 
                                126                 :     /* Size of copy buffer (read and write requests) */
                                127                 : #define COPY_BUF_SIZE (8 * BLCKSZ)
                                128                 : 
                                129                 :     /*
                                130                 :      * Size of data flush requests.  It seems beneficial on most platforms to
                                131                 :      * do this every 1MB or so.  But macOS, at least with early releases of
 2009 tgl                       132 ECB             :      * APFS, is really unfriendly to small mmap/msync requests, so there do it
                                133                 :      * only every 32MB.
                                134                 :      */
                                135                 : #if defined(__darwin__)
                                136                 : #define FLUSH_DISTANCE (32 * 1024 * 1024)
                                137                 : #else
                                138                 : #define FLUSH_DISTANCE (1024 * 1024)
 2009 tgl                       139 EUB             : #endif
                                140                 : 
                                141                 :     /* Use palloc to ensure we get a maxaligned buffer */
 6428 tgl                       142 GIC      185111 :     buffer = palloc(COPY_BUF_SIZE);
 6428 tgl                       143 ECB             : 
 6459                           144                 :     /*
 6459 tgl                       145 EUB             :      * Open the files
                                146                 :      */
 2024 peter_e                   147 GIC      185111 :     srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
 6459 tgl                       148          185111 :     if (srcfd < 0)
 6459 tgl                       149 UIC           0 :         ereport(ERROR,
                                150                 :                 (errcode_for_file_access(),
                                151                 :                  errmsg("could not open file \"%s\": %m", fromfile)));
 6459 tgl                       152 ECB             : 
 2024 peter_e                   153 CBC      185111 :     dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
 6459 tgl                       154 GIC      185111 :     if (dstfd < 0)
 6459 tgl                       155 UIC           0 :         ereport(ERROR,
 6459 tgl                       156 ECB             :                 (errcode_for_file_access(),
                                157                 :                  errmsg("could not create file \"%s\": %m", tofile)));
                                158                 : 
                                159                 :     /*
                                160                 :      * Do the data copying.
                                161                 :      */
 2009 tgl                       162 GIC      185111 :     flush_offset = 0;
 4790 bruce                     163 CBC      372060 :     for (offset = 0;; offset += nbytes)
                                164                 :     {
 4660 bruce                     165 ECB             :         /* If we got a cancel signal during the copy of the file, quit */
 4660 bruce                     166 CBC      372060 :         CHECK_FOR_INTERRUPTS();
                                167                 : 
                                168                 :         /*
 2009 tgl                       169 ECB             :          * We fsync the files later, but during the copy, flush them every so
                                170                 :          * often to avoid spamming the cache and hopefully get the kernel to
                                171                 :          * start writing them out before the fsync comes.
                                172                 :          */
 2009 tgl                       173 GBC      372060 :         if (offset - flush_offset >= FLUSH_DISTANCE)
                                174                 :         {
 2009 tgl                       175 GIC          32 :             pg_flush_data(dstfd, flush_offset, offset - flush_offset);
 2009 tgl                       176 CBC          32 :             flush_offset = offset;
 2009 tgl                       177 ECB             :         }
                                178                 : 
 2213 rhaas                     179 CBC      372060 :         pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_READ);
 6428 tgl                       180          372060 :         nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
 2213 rhaas                     181 GIC      372060 :         pgstat_report_wait_end();
 6459 tgl                       182          372060 :         if (nbytes < 0)
 6459 tgl                       183 UBC           0 :             ereport(ERROR,
 6459 tgl                       184 EUB             :                     (errcode_for_file_access(),
                                185                 :                      errmsg("could not read file \"%s\": %m", fromfile)));
 6459 tgl                       186 GIC      372060 :         if (nbytes == 0)
                                187          185111 :             break;
                                188          186949 :         errno = 0;
 2213 rhaas                     189 CBC      186949 :         pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_WRITE);
 6459 tgl                       190 GIC      186949 :         if ((int) write(dstfd, buffer, nbytes) != nbytes)
                                191                 :         {
 6459 tgl                       192 ECB             :             /* if write didn't set errno, assume problem is no disk space */
 6459 tgl                       193 LBC           0 :             if (errno == 0)
 6459 tgl                       194 UIC           0 :                 errno = ENOSPC;
 6459 tgl                       195 LBC           0 :             ereport(ERROR,
 7188 bruce                     196 EUB             :                     (errcode_for_file_access(),
                                197                 :                      errmsg("could not write to file \"%s\": %m", tofile)));
                                198                 :         }
 2213 rhaas                     199 GIC      186949 :         pgstat_report_wait_end();
 4801 stark                     200 ECB             :     }
 7269 bruce                     201 EUB             : 
 2009 tgl                       202 GIC      185111 :     if (offset > flush_offset)
                                203          153440 :         pg_flush_data(dstfd, flush_offset, offset - flush_offset);
                                204                 : 
 1373 peter                     205 CBC      185111 :     if (CloseTransientFile(dstfd) != 0)
 6459 tgl                       206 LBC           0 :         ereport(ERROR,
                                207                 :                 (errcode_for_file_access(),
                                208                 :                  errmsg("could not close file \"%s\": %m", tofile)));
                                209                 : 
 1373 peter                     210 GIC      185111 :     if (CloseTransientFile(srcfd) != 0)
 1492 michael                   211 UIC           0 :         ereport(ERROR,
                                212                 :                 (errcode_for_file_access(),
                                213                 :                  errmsg("could not close file \"%s\": %m", fromfile)));
                                214                 : 
 6428 tgl                       215 GIC      185111 :     pfree(buffer);
 7269 bruce                     216          185111 : }
        

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