1/*-------------------------------------------------------------------------
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
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
14 * src/backend/storage/file/copydir.c
16 *-------------------------------------------------------------------------
36static void clone_file(
const char *fromfile,
const char *tofile);
39 * copydir: copy a directory
41 * If recurse is false, subdirectories are ignored. Anything that's not
42 * a directory or a regular file is ignored.
44 * This function uses the file_copy_method GUC. New uses of this function must
45 * be documented in doc/src/sgml/config.sgml.
48 copydir(
const char *fromdir,
const char *todir,
bool recurse)
58 errmsg(
"could not create directory \"%s\": %m", todir)));
62 while ((xlde =
ReadDir(xldir, fromdir)) != NULL)
66 /* If we got a cancel signal during the copy of the directory, quit */
69 if (strcmp(xlde->
d_name,
".") == 0 ||
70 strcmp(xlde->
d_name,
"..") == 0)
73 snprintf(fromfile,
sizeof(fromfile),
"%s/%s", fromdir, xlde->
d_name);
80 /* recurse to handle subdirectories */
82 copydir(fromfile, tofile,
true);
95 * Be paranoid here and fsync all files to ensure the copy is really done.
96 * But if fsync is disabled, we're done.
103 while ((xlde =
ReadDir(xldir, todir)) != NULL)
105 if (strcmp(xlde->
d_name,
".") == 0 ||
106 strcmp(xlde->
d_name,
"..") == 0)
112 * We don't need to sync subdirectories here since the recursive
113 * copydir will do it before it returns
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.
142 /* Size of copy buffer (read and write requests) */
143#define COPY_BUF_SIZE (8 * BLCKSZ)
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
151#if defined(__darwin__)
152#define FLUSH_DISTANCE (32 * 1024 * 1024)
154#define FLUSH_DISTANCE (1024 * 1024)
157 /* Use palloc to ensure we get a maxaligned buffer */
167 errmsg(
"could not open file \"%s\": %m", fromfile)));
173 errmsg(
"could not create file \"%s\": %m", tofile)));
176 * Do the data copying.
179 for (offset = 0;; offset += nbytes)
181 /* If we got a cancel signal during the copy of the file, quit */
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.
192 flush_offset = offset;
201 errmsg(
"could not read file \"%s\": %m", fromfile)));
206 if ((
int)
write(
dstfd, buffer, nbytes) != nbytes)
208 /* if write didn't set errno, assume problem is no disk space */
213 errmsg(
"could not write to file \"%s\": %m", tofile)));
218 if (offset > flush_offset)
224 errmsg(
"could not close file \"%s\": %m", tofile)));
229 errmsg(
"could not close file \"%s\": %m", fromfile)));
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",
246#elif defined(HAVE_COPY_FILE_RANGE)
255 errmsg(
"could not open file \"%s\": %m", fromfile)));
261 errmsg(
"could not create file \"%s\": %m", tofile)));
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.
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",
284 errmsg(
"could not close file \"%s\": %m", tofile)));
289 errmsg(
"could not close file \"%s\": %m", fromfile)));
291 /* If there is no CLONE support this function should not be called. */
static void clone_file(const char *fromfile, const char *tofile)
void copy_file(const char *fromfile, const char *tofile)
void copydir(const char *fromdir, const char *todir, bool recurse)
int errcode_for_file_access(void)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void pg_flush_data(int fd, off_t offset, off_t nbytes)
int MakePGDirectory(const char *directoryName)
int CloseTransientFile(int fd)
void fsync_fname(const char *fname, bool isdir)
DIR * AllocateDir(const char *dirname)
struct dirent * ReadDir(DIR *dir, const char *dirname)
int OpenTransientFile(const char *fileName, int fileFlags)
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
void pfree(void *pointer)
#define CHECK_FOR_INTERRUPTS()
static void pgstat_report_wait_start(uint32 wait_event_info)
static void pgstat_report_wait_end(void)