PostgreSQL Source Code git master
Loading...
Searching...
No Matches
copydir.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * copydir.c
4 * copies a directory
5 *
6 * Portions Copyright (c) 1996-2026, 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#ifdef HAVE_COPYFILE_H
22#include <copyfile.h>
23#endif
24#include <fcntl.h>
25#include <unistd.h>
26
27#include "common/file_utils.h"
28#include "miscadmin.h"
29#include "pgstat.h"
30#include "storage/copydir.h"
31#include "storage/fd.h"
32#include "utils/wait_event.h"
33
34/* GUCs */
36
37static void clone_file(const char *fromfile, const char *tofile);
38
39/*
40 * copydir: copy a directory
41 *
42 * If recurse is false, subdirectories are ignored. Anything that's not
43 * a directory or a regular file is ignored.
44 *
45 * This function uses the file_copy_method GUC. New uses of this function must
46 * be documented in doc/src/sgml/config.sgml.
47 */
48void
49copydir(const char *fromdir, const char *todir, bool recurse)
50{
51 DIR *xldir;
52 struct dirent *xlde;
53 char fromfile[MAXPGPATH * 2];
54 char tofile[MAXPGPATH * 2];
55
56 if (MakePGDirectory(todir) != 0)
59 errmsg("could not create directory \"%s\": %m", todir)));
60
62
63 while ((xlde = ReadDir(xldir, fromdir)) != NULL)
64 {
66
67 /* If we got a cancel signal during the copy of the directory, quit */
69
70 if (strcmp(xlde->d_name, ".") == 0 ||
71 strcmp(xlde->d_name, "..") == 0)
72 continue;
73
74 snprintf(fromfile, sizeof(fromfile), "%s/%s", fromdir, xlde->d_name);
75 snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
76
78
80 {
81 /* recurse to handle subdirectories */
82 if (recurse)
83 copydir(fromfile, tofile, true);
84 }
85 else if (xlde_type == PGFILETYPE_REG)
86 {
89 else
91 }
92 }
94
95 /*
96 * Be paranoid here and fsync all files to ensure the copy is really done.
97 * But if fsync is disabled, we're done.
98 */
99 if (!enableFsync)
100 return;
101
103
104 while ((xlde = ReadDir(xldir, todir)) != NULL)
105 {
106 if (strcmp(xlde->d_name, ".") == 0 ||
107 strcmp(xlde->d_name, "..") == 0)
108 continue;
109
110 snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
111
112 /*
113 * We don't need to sync subdirectories here since the recursive
114 * copydir will do it before it returns
115 */
117 fsync_fname(tofile, false);
118 }
119 FreeDir(xldir);
120
121 /*
122 * It's important to fsync the destination directory itself as individual
123 * file fsyncs don't guarantee that the directory entry for the file is
124 * synced. Recent versions of ext4 have made the window much wider but
125 * it's been true for ext3 and other filesystems in the past.
126 */
127 fsync_fname(todir, true);
128}
129
130/*
131 * copy one file
132 */
133void
134copy_file(const char *fromfile, const char *tofile)
135{
136 char *buffer;
137 int srcfd;
138 int dstfd;
139 int nbytes;
140 off_t offset;
142
143 /* Size of copy buffer (read and write requests) */
144#define COPY_BUF_SIZE (8 * BLCKSZ)
145
146 /*
147 * Size of data flush requests. It seems beneficial on most platforms to
148 * do this every 1MB or so. But macOS, at least with early releases of
149 * APFS, is really unfriendly to small mmap/msync requests, so there do it
150 * only every 32MB.
151 */
152#if defined(__darwin__)
153#define FLUSH_DISTANCE (32 * 1024 * 1024)
154#else
155#define FLUSH_DISTANCE (1024 * 1024)
156#endif
157
158 /* Use palloc to ensure we get a maxaligned buffer */
159 buffer = palloc(COPY_BUF_SIZE);
160
161 /*
162 * Open the files
163 */
165 if (srcfd < 0)
168 errmsg("could not open file \"%s\": %m", fromfile)));
169
171 if (dstfd < 0)
174 errmsg("could not create file \"%s\": %m", tofile)));
175
176 /*
177 * Do the data copying.
178 */
179 flush_offset = 0;
180 for (offset = 0;; offset += nbytes)
181 {
182 /* If we got a cancel signal during the copy of the file, quit */
184
185 /*
186 * We fsync the files later, but during the copy, flush them every so
187 * often to avoid spamming the cache and hopefully get the kernel to
188 * start writing them out before the fsync comes.
189 */
190 if (offset - flush_offset >= FLUSH_DISTANCE)
191 {
193 flush_offset = offset;
194 }
195
197 nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
199 if (nbytes < 0)
202 errmsg("could not read file \"%s\": %m", fromfile)));
203 if (nbytes == 0)
204 break;
205 errno = 0;
207 if ((int) write(dstfd, buffer, nbytes) != nbytes)
208 {
209 /* if write didn't set errno, assume problem is no disk space */
210 if (errno == 0)
211 errno = ENOSPC;
214 errmsg("could not write to file \"%s\": %m", tofile)));
215 }
217 }
218
219 if (offset > flush_offset)
221
222 if (CloseTransientFile(dstfd) != 0)
225 errmsg("could not close file \"%s\": %m", tofile)));
226
227 if (CloseTransientFile(srcfd) != 0)
230 errmsg("could not close file \"%s\": %m", fromfile)));
231
232 pfree(buffer);
233}
234
235/*
236 * clone one file
237 */
238static void
239clone_file(const char *fromfile, const char *tofile)
240{
241#if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
245 errmsg("could not clone file \"%s\" to \"%s\": %m",
246 fromfile, tofile)));
247#elif defined(HAVE_COPY_FILE_RANGE)
248 int srcfd;
249 int dstfd;
250 ssize_t nbytes;
251
253 if (srcfd < 0)
256 errmsg("could not open file \"%s\": %m", fromfile)));
257
259 if (dstfd < 0)
262 errmsg("could not create file \"%s\": %m", tofile)));
263
264 do
265 {
266 /*
267 * Don't copy too much at once, so we can check for interrupts from
268 * time to time if it falls back to a slow copy.
269 */
272 nbytes = copy_file_range(srcfd, NULL, dstfd, NULL, 1024 * 1024, 0);
273 if (nbytes < 0 && errno != EINTR)
276 errmsg("could not clone file \"%s\" to \"%s\": %m",
277 fromfile, tofile)));
279 }
280 while (nbytes != 0);
281
282 if (CloseTransientFile(dstfd) != 0)
285 errmsg("could not close file \"%s\": %m", tofile)));
286
287 if (CloseTransientFile(srcfd) != 0)
290 errmsg("could not close file \"%s\": %m", fromfile)));
291#else
292 /* If there is no CLONE support this function should not be called. */
294#endif
295}
#define PG_BINARY
Definition c.h:1376
#define pg_unreachable()
Definition c.h:361
#define FLUSH_DISTANCE
int file_copy_method
Definition copydir.c:35
static void clone_file(const char *fromfile, const char *tofile)
Definition copydir.c:239
#define COPY_BUF_SIZE
void copy_file(const char *fromfile, const char *tofile)
Definition copydir.c:134
void copydir(const char *fromdir, const char *todir, bool recurse)
Definition copydir.c:49
@ FILE_COPY_METHOD_COPY
Definition copydir.h:18
@ FILE_COPY_METHOD_CLONE
Definition copydir.h:19
int errcode_for_file_access(void)
Definition elog.c:897
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
int MakePGDirectory(const char *directoryName)
Definition fd.c:3963
int FreeDir(DIR *dir)
Definition fd.c:3009
int CloseTransientFile(int fd)
Definition fd.c:2855
void fsync_fname(const char *fname, bool isdir)
Definition fd.c:757
void pg_flush_data(int fd, pgoff_t offset, pgoff_t nbytes)
Definition fd.c:526
DIR * AllocateDir(const char *dirname)
Definition fd.c:2891
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition fd.c:2957
int OpenTransientFile(const char *fileName, int fileFlags)
Definition fd.c:2678
static int dstfd
Definition file_ops.c:31
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition file_utils.c:547
PGFileType
Definition file_utils.h:19
@ PGFILETYPE_DIR
Definition file_utils.h:23
@ PGFILETYPE_REG
Definition file_utils.h:22
bool enableFsync
Definition globals.c:129
#define write(a, b, c)
Definition win32.h:14
#define read(a, b, c)
Definition win32.h:13
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
static char * errmsg
#define MAXPGPATH
#define snprintf
Definition port.h:260
static int fb(int x)
Definition dirent.c:26
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition wait_event.h:69
static void pgstat_report_wait_end(void)
Definition wait_event.h:85
#define EINTR
Definition win32_port.h:361