PostgreSQL Source Code git master
copy_file.c File Reference
#include "postgres_fe.h"
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <unistd.h>
#include "common/file_perm.h"
#include "common/logging.h"
#include "copy_file.h"
Include dependency graph for copy_file.c:

Go to the source code of this file.

Functions

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)
 
static void copy_file_by_range (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)
 

Function Documentation

◆ checksum_file()

static void checksum_file ( const char *  src,
pg_checksum_context checksum_ctx 
)
static

Definition at line 127 of file copy_file.c.

128{
129 int src_fd;
130 uint8 *buffer;
131 const int buffer_size = 50 * BLCKSZ;
132 ssize_t rb;
133
134 /* bail out if no checksum needed */
135 if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
136 return;
137
138 if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
139 pg_fatal("could not open file \"%s\": %m", src);
140
141 buffer = pg_malloc(buffer_size);
142
143 while ((rb = read(src_fd, buffer, buffer_size)) > 0)
144 {
145 if (pg_checksum_update(checksum_ctx, buffer, rb) < 0)
146 pg_fatal("could not update checksum of file \"%s\"", src);
147 }
148
149 if (rb < 0)
150 pg_fatal("could not read file \"%s\": %m", src);
151
152 pg_free(buffer);
153 close(src_fd);
154}
uint8_t uint8
Definition: c.h:486
#define PG_BINARY
Definition: c.h:1230
int pg_checksum_update(pg_checksum_context *context, const uint8 *input, size_t len)
@ CHECKSUM_TYPE_NONE
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void pg_free(void *ptr)
Definition: fe_memutils.c:105
#define close(a)
Definition: win32.h:12
#define read(a, b, c)
Definition: win32.h:13
#define pg_fatal(...)
pg_checksum_type type

References CHECKSUM_TYPE_NONE, close, PG_BINARY, pg_checksum_update(), pg_fatal, pg_free(), pg_malloc(), read, and pg_checksum_context::type.

Referenced by copy_file_by_range(), and copy_file_clone().

◆ copy_file()

void copy_file ( const char *  src,
const char *  dst,
pg_checksum_context checksum_ctx,
CopyMethod  copy_method,
bool  dry_run 
)

Definition at line 49 of file copy_file.c.

52{
53 char *strategy_name = NULL;
54 void (*strategy_implementation) (const char *, const char *,
55 pg_checksum_context *checksum_ctx) = NULL;
56
57 /*
58 * In dry-run mode, we don't actually copy anything, nor do we read any
59 * data from the source file, but we do verify that we can open it.
60 */
61 if (dry_run)
62 {
63 int fd;
64
65 if ((fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
66 pg_fatal("could not open file \"%s\": %m", src);
67 if (close(fd) < 0)
68 pg_fatal("could not close file \"%s\": %m", src);
69 }
70
71#ifdef WIN32
72 copy_method = COPY_METHOD_COPYFILE;
73#endif
74
75 /* Determine the name of the copy strategy for use in log messages. */
76 switch (copy_method)
77 {
79 strategy_name = "clone";
80 strategy_implementation = copy_file_clone;
81 break;
83 /* leave NULL for simple block-by-block copy */
84 strategy_implementation = copy_file_blocks;
85 break;
87 strategy_name = "copy_file_range";
88 strategy_implementation = copy_file_by_range;
89 break;
90#ifdef WIN32
91 case COPY_METHOD_COPYFILE:
92 strategy_name = "CopyFile";
93 strategy_implementation = copy_file_copyfile;
94 break;
95#endif
96 }
97
98 if (dry_run)
99 {
100 if (strategy_name)
101 pg_log_debug("would copy \"%s\" to \"%s\" using strategy %s",
102 src, dst, strategy_name);
103 else
104 pg_log_debug("would copy \"%s\" to \"%s\"",
105 src, dst);
106 }
107 else
108 {
109 if (strategy_name)
110 pg_log_debug("copying \"%s\" to \"%s\" using strategy %s",
111 src, dst, strategy_name);
112 else if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
113 pg_log_debug("copying \"%s\" to \"%s\"",
114 src, dst);
115 else
116 pg_log_debug("copying \"%s\" to \"%s\" and checksumming with %s",
117 src, dst, pg_checksum_type_name(checksum_ctx->type));
118
119 strategy_implementation(src, dst, checksum_ctx);
120 }
121}
char * pg_checksum_type_name(pg_checksum_type type)
static void copy_file_blocks(const char *src, const char *dst, pg_checksum_context *checksum_ctx)
Definition: copy_file.c:160
static void copy_file_clone(const char *src, const char *dest, pg_checksum_context *checksum_ctx)
Definition: copy_file.c:213
static void copy_file_by_range(const char *src, const char *dest, pg_checksum_context *checksum_ctx)
Definition: copy_file.c:259
@ COPY_METHOD_CLONE
Definition: copy_file.h:22
@ COPY_METHOD_COPY
Definition: copy_file.h:23
@ COPY_METHOD_COPY_FILE_RANGE
Definition: copy_file.h:24
#define pg_log_debug(...)
Definition: logging.h:133
static bool dry_run
static int fd(const char *x, int i)
Definition: preproc-init.c:105

References CHECKSUM_TYPE_NONE, close, copy_file_blocks(), copy_file_by_range(), copy_file_clone(), COPY_METHOD_CLONE, COPY_METHOD_COPY, COPY_METHOD_COPY_FILE_RANGE, dry_run, fd(), PG_BINARY, pg_checksum_type_name(), pg_fatal, pg_log_debug, and pg_checksum_context::type.

◆ copy_file_blocks()

static void copy_file_blocks ( const char *  src,
const char *  dst,
pg_checksum_context checksum_ctx 
)
static

Definition at line 160 of file copy_file.c.

162{
163 int src_fd;
164 int dest_fd;
165 uint8 *buffer;
166 const int buffer_size = 50 * BLCKSZ;
167 ssize_t rb;
168 unsigned offset = 0;
169
170 if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
171 pg_fatal("could not open file \"%s\": %m", src);
172
173 if ((dest_fd = open(dst, O_WRONLY | O_CREAT | O_EXCL | PG_BINARY,
175 pg_fatal("could not open file \"%s\": %m", dst);
176
177 buffer = pg_malloc(buffer_size);
178
179 while ((rb = read(src_fd, buffer, buffer_size)) > 0)
180 {
181 ssize_t wb;
182
183 if ((wb = write(dest_fd, buffer, rb)) != rb)
184 {
185 if (wb < 0)
186 pg_fatal("could not write to file \"%s\": %m", dst);
187 else
188 pg_fatal("could not write to file \"%s\", offset %u: wrote %d of %d",
189 dst, offset, (int) wb, (int) rb);
190 }
191
192 if (pg_checksum_update(checksum_ctx, buffer, rb) < 0)
193 pg_fatal("could not update checksum of file \"%s\"", dst);
194
195 offset += rb;
196 }
197
198 if (rb < 0)
199 pg_fatal("could not read from file \"%s\": %m", dst);
200
201 pg_free(buffer);
202 close(src_fd);
203 close(dest_fd);
204}
int pg_file_create_mode
Definition: file_perm.c:19
#define write(a, b, c)
Definition: win32.h:14

References close, PG_BINARY, pg_checksum_update(), pg_fatal, pg_file_create_mode, pg_free(), pg_malloc(), read, and write.

Referenced by copy_file().

◆ copy_file_by_range()

static void copy_file_by_range ( const char *  src,
const char *  dest,
pg_checksum_context checksum_ctx 
)
static

Definition at line 259 of file copy_file.c.

261{
262#if defined(HAVE_COPY_FILE_RANGE)
263 int src_fd;
264 int dest_fd;
265 ssize_t nbytes;
266
267 if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
268 pg_fatal("could not open file \"%s\": %m", src);
269
270 if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
272 pg_fatal("could not create file \"%s\": %m", dest);
273
274 do
275 {
276 nbytes = copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0);
277 if (nbytes < 0)
278 pg_fatal("error while copying file range from \"%s\" to \"%s\": %m",
279 src, dest);
280 } while (nbytes > 0);
281
282 close(src_fd);
283 close(dest_fd);
284#else
285 pg_fatal("copy_file_range not supported on this platform");
286#endif
287
288 /* if needed, calculate checksum of the file */
289 checksum_file(src, checksum_ctx);
290}
static void checksum_file(const char *src, pg_checksum_context *checksum_ctx)
Definition: copy_file.c:127

References checksum_file(), close, generate_unaccent_rules::dest, PG_BINARY, pg_fatal, and pg_file_create_mode.

Referenced by copy_file().

◆ copy_file_clone()

static void copy_file_clone ( const char *  src,
const char *  dest,
pg_checksum_context checksum_ctx 
)
static

Definition at line 213 of file copy_file.c.

215{
216#if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
217 if (copyfile(src, dest, NULL, COPYFILE_CLONE_FORCE) < 0)
218 pg_fatal("error while cloning file \"%s\" to \"%s\": %m", src, dest);
219#elif defined(__linux__) && defined(FICLONE)
220 {
221 int src_fd;
222 int dest_fd;
223
224 if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
225 pg_fatal("could not open file \"%s\": %m", src);
226
227 if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
229 pg_fatal("could not create file \"%s\": %m", dest);
230
231 if (ioctl(dest_fd, FICLONE, src_fd) < 0)
232 {
233 int save_errno = errno;
234
235 unlink(dest);
236
237 pg_fatal("error while cloning file \"%s\" to \"%s\": %s",
238 src, dest, strerror(save_errno));
239 }
240
241 close(src_fd);
242 close(dest_fd);
243 }
244#else
245 pg_fatal("file cloning not supported on this platform");
246#endif
247
248 /* if needed, calculate checksum of the file */
249 checksum_file(src, checksum_ctx);
250}
#define strerror
Definition: port.h:252

References checksum_file(), close, generate_unaccent_rules::dest, PG_BINARY, pg_fatal, pg_file_create_mode, and strerror.

Referenced by copy_file().