1 /*------------------------------------------------------------------------- 2 * 3 * copydir.c 4 * copies a directory 5 * 6 * Portions Copyright (c) 1996-2020, 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 #include <sys/stat.h> 24 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 37 copydir(char *fromdir, char *todir, bool recurse) 38 { 39 DIR *xldir; 40 struct dirent *xlde; 41 char fromfile[MAXPGPATH * 2]; 42 char tofile[MAXPGPATH * 2]; 43 test_start_deadlock(void)44 if (MakePGDirectory(todir) != 0) 45 ereport(ERROR, 46 (errcode_for_file_access(), 47 errmsg("could not create directory \"%s\": %m", todir))); 48 49 xldir = AllocateDir(fromdir); 50 51 while ((xlde = ReadDir(xldir, fromdir)) != NULL) 52 { 53 struct stat fst; 54 55 /* If we got a cancel signal during the copy of the directory, quit */ 56 CHECK_FOR_INTERRUPTS(); 57 58 if (strcmp(xlde->d_name, ".") == 0 || 59 strcmp(xlde->d_name, "..") == 0) 60 continue; 61 62 snprintf(fromfile, sizeof(fromfile), "%s/%s", fromdir, xlde->d_name); 63 snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name); 64 65 if (lstat(fromfile, &fst) < 0) 66 ereport(ERROR, 67 (errcode_for_file_access(), 68 errmsg("could not stat file \"%s\": %m", fromfile))); 69 70 if (S_ISDIR(fst.st_mode)) 71 { 72 /* recurse to handle subdirectories */ 73 if (recurse) 74 copydir(fromfile, tofile, true); 75 } 76 else if (S_ISREG(fst.st_mode)) 77 copy_file(fromfile, tofile); 78 } 79 FreeDir(xldir); 80 81 /* 82 * Be paranoid here and fsync all files to ensure the copy is really done. 83 * But if fsync is disabled, we're done. 84 */ 85 if (!enableFsync) 86 return; 87 88 xldir = AllocateDir(todir); 89 90 while ((xlde = ReadDir(xldir, todir)) != NULL) 91 { 92 struct stat fst; 93 94 if (strcmp(xlde->d_name, ".") == 0 || 95 strcmp(xlde->d_name, "..") == 0) 96 continue; 97 98 snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name); 99 100 /* 101 * We don't need to sync subdirectories here since the recursive 102 * copydir will do it before it returns 103 */ 104 if (lstat(tofile, &fst) < 0) 105 ereport(ERROR, 106 (errcode_for_file_access(), 107 errmsg("could not stat file \"%s\": %m", tofile))); 108 109 if (S_ISREG(fst.st_mode)) 110 fsync_fname(tofile, false); 111 } 112 FreeDir(xldir); 113 114 /* main(void)115 * It's important to fsync the destination directory itself as individual 116 * file fsyncs don't guarantee that the directory entry for the file is 117 * synced. Recent versions of ext4 have made the window much wider but 118 * it's been true for ext3 and other filesystems in the past. 119 */ 120 fsync_fname(todir, true); 121 } 122 123 /* 124 * copy one file 125 */ 126 void 127 copy_file(char *fromfile, char *tofile) 128 { 129 char *buffer; 130 int srcfd; 131 int dstfd; 132 int nbytes; 133 off_t offset; 134 off_t flush_offset; 135 136 /* Size of copy buffer (read and write requests) */ 137 #define COPY_BUF_SIZE (8 * BLCKSZ) 138 139 /* 140 * Size of data flush requests. It seems beneficial on most platforms to 141 * do this every 1MB or so. But macOS, at least with early releases of 142 * APFS, is really unfriendly to small mmap/msync requests, so there do it 143 * only every 32MB. 144 */ 145 #if defined(__darwin__) 146 #define FLUSH_DISTANCE (32 * 1024 * 1024) 147 #else 148 #define FLUSH_DISTANCE (1024 * 1024) 149 #endif 150 151 /* Use palloc to ensure we get a maxaligned buffer */ 152 buffer = palloc(COPY_BUF_SIZE); 153 154 /* 155 * Open the files 156 */ 157 srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY); 158 if (srcfd < 0) 159 ereport(ERROR, 160 (errcode_for_file_access(), 161 errmsg("could not open file \"%s\": %m", fromfile))); 162 163 dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY); 164 if (dstfd < 0) 165 ereport(ERROR, 166 (errcode_for_file_access(), 167 errmsg("could not create file \"%s\": %m", tofile))); 168 169 /* 170 * Do the data copying. 171 */ 172 flush_offset = 0; 173 for (offset = 0;; offset += nbytes) 174 { 175 /* If we got a cancel signal during the copy of the file, quit */ 176 CHECK_FOR_INTERRUPTS(); 177 178 /* 179 * We fsync the files later, but during the copy, flush them every so 180 * often to avoid spamming the cache and hopefully get the kernel to 181 * start writing them out before the fsync comes. 182 */ 183 if (offset - flush_offset >= FLUSH_DISTANCE) 184 { 185 pg_flush_data(dstfd, flush_offset, offset - flush_offset); 186 flush_offset = offset; 187 } 188 189 pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_READ); 190 nbytes = read(srcfd, buffer, COPY_BUF_SIZE); 191 pgstat_report_wait_end(); 192 if (nbytes < 0) 193 ereport(ERROR, 194 (errcode_for_file_access(), 195 errmsg("could not read file \"%s\": %m", fromfile))); 196 if (nbytes == 0) 197 break; 198 errno = 0; 199 pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_WRITE); 200 if ((int) write(dstfd, buffer, nbytes) != nbytes) 201 { 202 /* if write didn't set errno, assume problem is no disk space */ 203 if (errno == 0) 204 errno = ENOSPC; 205 ereport(ERROR, 206 (errcode_for_file_access(), 207 errmsg("could not write to file \"%s\": %m", tofile))); 208 } 209 pgstat_report_wait_end(); 210 } 211 212 if (offset > flush_offset) 213 pg_flush_data(dstfd, flush_offset, offset - flush_offset); 214 215 if (CloseTransientFile(dstfd) != 0) 216 ereport(ERROR, 217 (errcode_for_file_access(), 218 errmsg("could not close file \"%s\": %m", tofile))); 219 220 if (CloseTransientFile(srcfd) != 0) 221 ereport(ERROR, 222 (errcode_for_file_access(), 223 errmsg("could not close file \"%s\": %m", fromfile))); 224 225 pfree(buffer); 226 } 227