PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
copydir.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * copydir.c
4 * copies a directory
5 *
6 * Portions Copyright (c) 1996-2025, 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
33/* GUCs */
35
36static void clone_file(const char *fromfile, const char *tofile);
37
38/*
39 * copydir: copy a directory
40 *
41 * If recurse is false, subdirectories are ignored. Anything that's not
42 * a directory or a regular file is ignored.
43 *
44 * This function uses the file_copy_method GUC. New uses of this function must
45 * be documented in doc/src/sgml/config.sgml.
46 */
47void
48copydir(const char *fromdir, const char *todir, bool recurse)
49{
50 DIR *xldir;
51 struct dirent *xlde;
52 char fromfile[MAXPGPATH * 2];
53 char tofile[MAXPGPATH * 2];
54
55 if (MakePGDirectory(todir) != 0)
58 errmsg("could not create directory \"%s\": %m", todir)));
59
60 xldir = AllocateDir(fromdir);
61
62 while ((xlde = ReadDir(xldir, fromdir)) != NULL)
63 {
64 PGFileType xlde_type;
65
66 /* If we got a cancel signal during the copy of the directory, quit */
68
69 if (strcmp(xlde->d_name, ".") == 0 ||
70 strcmp(xlde->d_name, "..") == 0)
71 continue;
72
73 snprintf(fromfile, sizeof(fromfile), "%s/%s", fromdir, xlde->d_name);
74 snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
75
76 xlde_type = get_dirent_type(fromfile, xlde, false, ERROR);
77
78 if (xlde_type == PGFILETYPE_DIR)
79 {
80 /* recurse to handle subdirectories */
81 if (recurse)
82 copydir(fromfile, tofile, true);
83 }
84 else if (xlde_type == PGFILETYPE_REG)
85 {
87 clone_file(fromfile, tofile);
88 else
89 copy_file(fromfile, tofile);
90 }
91 }
92 FreeDir(xldir);
93
94 /*
95 * Be paranoid here and fsync all files to ensure the copy is really done.
96 * But if fsync is disabled, we're done.
97 */
98 if (!enableFsync)
99 return;
100
101 xldir = AllocateDir(todir);
102
103 while ((xlde = ReadDir(xldir, todir)) != NULL)
104 {
105 if (strcmp(xlde->d_name, ".") == 0 ||
106 strcmp(xlde->d_name, "..") == 0)
107 continue;
108
109 snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
110
111 /*
112 * We don't need to sync subdirectories here since the recursive
113 * copydir will do it before it returns
114 */
115 if (get_dirent_type(tofile, xlde, false, ERROR) == PGFILETYPE_REG)
116 fsync_fname(tofile, false);
117 }
118 FreeDir(xldir);
119
120 /*
121 * It's important to fsync the destination directory itself as individual
122 * file fsyncs don't guarantee that the directory entry for the file is
123 * synced. Recent versions of ext4 have made the window much wider but
124 * it's been true for ext3 and other filesystems in the past.
125 */
126 fsync_fname(todir, true);
127}
128
129/*
130 * copy one file
131 */
132void
133copy_file(const char *fromfile, const char *tofile)
134{
135 char *buffer;
136 int srcfd;
137 int dstfd;
138 int nbytes;
139 off_t offset;
140 off_t flush_offset;
141
142 /* Size of copy buffer (read and write requests) */
143#define COPY_BUF_SIZE (8 * BLCKSZ)
144
145 /*
146 * Size of data flush requests. It seems beneficial on most platforms to
147 * do this every 1MB or so. But macOS, at least with early releases of
148 * APFS, is really unfriendly to small mmap/msync requests, so there do it
149 * only every 32MB.
150 */
151#if defined(__darwin__)
152#define FLUSH_DISTANCE (32 * 1024 * 1024)
153#else
154#define FLUSH_DISTANCE (1024 * 1024)
155#endif
156
157 /* Use palloc to ensure we get a maxaligned buffer */
158 buffer = palloc(COPY_BUF_SIZE);
159
160 /*
161 * Open the files
162 */
163 srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
164 if (srcfd < 0)
167 errmsg("could not open file \"%s\": %m", fromfile)));
168
169 dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
170 if (dstfd < 0)
173 errmsg("could not create file \"%s\": %m", tofile)));
174
175 /*
176 * Do the data copying.
177 */
178 flush_offset = 0;
179 for (offset = 0;; offset += nbytes)
180 {
181 /* If we got a cancel signal during the copy of the file, quit */
183
184 /*
185 * We fsync the files later, but during the copy, flush them every so
186 * often to avoid spamming the cache and hopefully get the kernel to
187 * start writing them out before the fsync comes.
188 */
189 if (offset - flush_offset >= FLUSH_DISTANCE)
190 {
191 pg_flush_data(dstfd, flush_offset, offset - flush_offset);
192 flush_offset = offset;
193 }
194
195 pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_READ);
196 nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
198 if (nbytes < 0)
201 errmsg("could not read file \"%s\": %m", fromfile)));
202 if (nbytes == 0)
203 break;
204 errno = 0;
205 pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_WRITE);
206 if ((int) write(dstfd, buffer, nbytes) != nbytes)
207 {
208 /* if write didn't set errno, assume problem is no disk space */
209 if (errno == 0)
210 errno = ENOSPC;
213 errmsg("could not write to file \"%s\": %m", tofile)));
214 }
216 }
217
218 if (offset > flush_offset)
219 pg_flush_data(dstfd, flush_offset, offset - flush_offset);
220
221 if (CloseTransientFile(dstfd) != 0)
224 errmsg("could not close file \"%s\": %m", tofile)));
225
226 if (CloseTransientFile(srcfd) != 0)
229 errmsg("could not close file \"%s\": %m", fromfile)));
230
231 pfree(buffer);
232}
233
234/*
235 * clone one file
236 */
237static void
238clone_file(const char *fromfile, const char *tofile)
239{
240#if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
241 if (copyfile(fromfile, tofile, NULL, COPYFILE_CLONE_FORCE) < 0)
244 errmsg("could not clone file \"%s\" to \"%s\": %m",
245 fromfile, tofile)));
246#elif defined(HAVE_COPY_FILE_RANGE)
247 int srcfd;
248 int dstfd;
249 ssize_t nbytes;
250
251 srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
252 if (srcfd < 0)
255 errmsg("could not open file \"%s\": %m", fromfile)));
256
257 dstfd = OpenTransientFile(tofile, O_WRONLY | O_CREAT | O_EXCL | PG_BINARY);
258 if (dstfd < 0)
261 errmsg("could not create file \"%s\": %m", tofile)));
262
263 do
264 {
265 /*
266 * Don't copy too much at once, so we can check for interrupts from
267 * time to time if it falls back to a slow copy.
268 */
270 pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_COPY);
271 nbytes = copy_file_range(srcfd, NULL, dstfd, NULL, 1024 * 1024, 0);
272 if (nbytes < 0 && errno != EINTR)
275 errmsg("could not clone file \"%s\" to \"%s\": %m",
276 fromfile, tofile)));
278 }
279 while (nbytes != 0);
280
281 if (CloseTransientFile(dstfd) != 0)
284 errmsg("could not close file \"%s\": %m", tofile)));
285
286 if (CloseTransientFile(srcfd) != 0)
289 errmsg("could not close file \"%s\": %m", fromfile)));
290#else
291 /* If there is no CLONE support this function should not be called. */
293#endif
294}
#define PG_BINARY
Definition: c.h:1244
#define pg_unreachable()
Definition: c.h:332
#define FLUSH_DISTANCE
int file_copy_method
Definition: copydir.c:34
static void clone_file(const char *fromfile, const char *tofile)
Definition: copydir.c:238
#define COPY_BUF_SIZE
void copy_file(const char *fromfile, const char *tofile)
Definition: copydir.c:133
void copydir(const char *fromdir, const char *todir, bool recurse)
Definition: copydir.c:48
@ 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:877
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void pg_flush_data(int fd, off_t offset, off_t nbytes)
Definition: fd.c:525
int MakePGDirectory(const char *directoryName)
Definition: fd.c:3978
int FreeDir(DIR *dir)
Definition: fd.c:3025
int CloseTransientFile(int fd)
Definition: fd.c:2871
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:756
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2907
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2973
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2694
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:130
#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:2150
void * palloc(Size size)
Definition: mcxt.c:1943
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:123
#define MAXPGPATH
#define snprintf
Definition: port.h:239
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
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:364