4 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
5 * Portions Copyright (c) 1994, Regents of the University of California
7 * src/bin/pg_combinebackup/copy_file.c
9 *-------------------------------------------------------------------------
39static void copy_file_copyfile(
const char *src,
const char *dst,
47 * Copy a regular file, optionally computing a checksum, and emitting
48 * appropriate debug messages. But if we're in dry-run mode, then just emit
49 * the messages and don't copy anything.
56 char *strategy_name = NULL;
57 void (*strategy_implementation) (
const char *,
const char *,
61 * In dry-run mode, we don't actually copy anything, nor do we read any
62 * data from the source file, but we do verify that we can open it.
69 pg_fatal(
"could not open file \"%s\": %m", src);
71 pg_fatal(
"could not close file \"%s\": %m", src);
77 * We have no specific switch to enable CopyFile on Windows, because it's
78 * supported (as far as we know) on all Windows machines. So,
79 * automatically enable it unless some other strategy was selected.
82 copy_method = COPY_METHOD_COPYFILE;
85 /* Determine the name of the copy strategy for use in log messages. */
89 strategy_name =
"clone";
93 /* leave NULL for simple block-by-block copy */
97 strategy_name =
"copy_file_range";
101 case COPY_METHOD_COPYFILE:
102 strategy_name =
"CopyFile";
103 strategy_implementation = copy_file_copyfile;
107 strategy_name =
"link";
115 pg_log_debug(
"would copy \"%s\" to \"%s\" using strategy %s",
116 src, dst, strategy_name);
124 pg_log_debug(
"copying \"%s\" to \"%s\" using strategy %s",
125 src, dst, strategy_name);
130 pg_log_debug(
"copying \"%s\" to \"%s\" and checksumming with %s",
133 strategy_implementation(src, dst, checksum_ctx);
138 * Calculate checksum for the src file.
145 const int buffer_size = 50 * BLCKSZ;
148 /* bail out if no checksum needed */
152 if ((src_fd = open(src, O_RDONLY |
PG_BINARY, 0)) < 0)
153 pg_fatal(
"could not open file \"%s\": %m", src);
157 while ((rb =
read(src_fd, buffer, buffer_size)) > 0)
160 pg_fatal(
"could not update checksum of file \"%s\"", src);
164 pg_fatal(
"could not read file \"%s\": %m", src);
171 * Copy a file block by block, and optionally compute a checksum as we go.
180 const int buffer_size = 50 * BLCKSZ;
184 if ((src_fd = open(src, O_RDONLY |
PG_BINARY, 0)) < 0)
185 pg_fatal(
"could not open file \"%s\": %m", src);
187 if ((dest_fd = open(dst, O_WRONLY | O_CREAT | O_EXCL |
PG_BINARY,
189 pg_fatal(
"could not open file \"%s\": %m", dst);
193 while ((rb =
read(src_fd, buffer, buffer_size)) > 0)
197 if ((wb =
write(dest_fd, buffer, rb)) != rb)
200 pg_fatal(
"could not write to file \"%s\": %m", dst);
202 pg_fatal(
"could not write to file \"%s\", offset %u: wrote %d of %d",
203 dst, offset, (
int) wb, (
int) rb);
207 pg_fatal(
"could not update checksum of file \"%s\"", dst);
213 pg_fatal(
"could not read from file \"%s\": %m", dst);
222 * Clones/reflinks a file from src to dest.
224 * If needed, also reads the file and calculates the checksum.
230#if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
231 if (copyfile(src,
dest, NULL, COPYFILE_CLONE_FORCE) < 0)
232 pg_fatal(
"error while cloning file \"%s\" to \"%s\": %m", src,
dest);
233#elif defined(__linux__) && defined(FICLONE)
238 if ((src_fd = open(src, O_RDONLY |
PG_BINARY, 0)) < 0)
239 pg_fatal(
"could not open file \"%s\": %m", src);
241 if ((dest_fd = open(
dest, O_RDWR | O_CREAT | O_EXCL |
PG_BINARY,
245 if (ioctl(dest_fd, FICLONE, src_fd) < 0)
247 int save_errno = errno;
251 pg_fatal(
"error while cloning file \"%s\" to \"%s\": %s",
259 pg_fatal(
"file cloning not supported on this platform");
262 /* if needed, calculate checksum of the file */
268 * Copies a file from src to dest using copy_file_range system call.
270 * If needed, also reads the file and calculates the checksum.
276#if defined(HAVE_COPY_FILE_RANGE)
281 if ((src_fd = open(src, O_RDONLY |
PG_BINARY, 0)) < 0)
282 pg_fatal(
"could not open file \"%s\": %m", src);
284 if ((dest_fd = open(
dest, O_RDWR | O_CREAT | O_EXCL |
PG_BINARY,
290 nbytes = copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0);
292 pg_fatal(
"error while copying file range from \"%s\" to \"%s\": %m",
294 }
while (nbytes > 0);
299 pg_fatal(
"copy_file_range not supported on this platform");
302 /* if needed, calculate checksum of the file */
308copy_file_copyfile(
const char *src,
const char *dst,
311 if (CopyFile(src, dst,
true) == 0)
314 pg_fatal(
"could not copy file \"%s\" to \"%s\": %m", src, dst);
317 /* if needed, calculate checksum of the file */
324 * Hard-links a file from src to dest.
326 * If needed, also reads the file and calculates the checksum.
333 pg_fatal(
"could not create link from \"%s\" to \"%s\": %m",
336 /* if needed, calculate checksum of the file */
char * pg_checksum_type_name(pg_checksum_type type)
int pg_checksum_update(pg_checksum_context *context, const uint8 *input, size_t len)
static void copy_file_blocks(const char *src, const char *dst, pg_checksum_context *checksum_ctx)
static void copy_file_clone(const char *src, const char *dest, pg_checksum_context *checksum_ctx)
void copy_file(const char *src, const char *dst, pg_checksum_context *checksum_ctx, CopyMethod copy_method, bool dry_run)
static void checksum_file(const char *src, pg_checksum_context *checksum_ctx)
static void copy_file_link(const char *src, const char *dest, pg_checksum_context *checksum_ctx)
static void copy_file_by_range(const char *src, const char *dest, pg_checksum_context *checksum_ctx)
@ COPY_METHOD_COPY_FILE_RANGE
void * pg_malloc(size_t size)
#define pg_log_debug(...)
static int fd(const char *x, int i)
void _dosmaperr(unsigned long)
int link(const char *src, const char *dst)