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)
 
static void copy_file_link (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 141 of file copy_file.c.

142{
143 int src_fd;
144 uint8 *buffer;
145 const int buffer_size = 50 * BLCKSZ;
146 ssize_t rb;
147
148 /* bail out if no checksum needed */
149 if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
150 return;
151
152 if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
153 pg_fatal("could not open file \"%s\": %m", src);
154
155 buffer = pg_malloc(buffer_size);
156
157 while ((rb = read(src_fd, buffer, buffer_size)) > 0)
158 {
159 if (pg_checksum_update(checksum_ctx, buffer, rb) < 0)
160 pg_fatal("could not update checksum of file \"%s\"", src);
161 }
162
163 if (rb < 0)
164 pg_fatal("could not read file \"%s\": %m", src);
165
166 pg_free(buffer);
167 close(src_fd);
168}
uint8_t uint8
Definition: c.h:500
#define PG_BINARY
Definition: c.h:1244
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(), copy_file_clone(), and copy_file_link().

◆ 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 52 of file copy_file.c.

55{
56 char *strategy_name = NULL;
57 void (*strategy_implementation) (const char *, const char *,
58 pg_checksum_context *checksum_ctx) = NULL;
59
60 /*
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.
63 */
64 if (dry_run)
65 {
66 int fd;
67
68 if ((fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
69 pg_fatal("could not open file \"%s\": %m", src);
70 if (close(fd) < 0)
71 pg_fatal("could not close file \"%s\": %m", src);
72 }
73
74#ifdef WIN32
75
76 /*
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.
80 */
81 if (copy_method == COPY_METHOD_COPY)
82 copy_method = COPY_METHOD_COPYFILE;
83#endif
84
85 /* Determine the name of the copy strategy for use in log messages. */
86 switch (copy_method)
87 {
89 strategy_name = "clone";
90 strategy_implementation = copy_file_clone;
91 break;
93 /* leave NULL for simple block-by-block copy */
94 strategy_implementation = copy_file_blocks;
95 break;
97 strategy_name = "copy_file_range";
98 strategy_implementation = copy_file_by_range;
99 break;
100#ifdef WIN32
101 case COPY_METHOD_COPYFILE:
102 strategy_name = "CopyFile";
103 strategy_implementation = copy_file_copyfile;
104 break;
105#endif
106 case COPY_METHOD_LINK:
107 strategy_name = "link";
108 strategy_implementation = copy_file_link;
109 break;
110 }
111
112 if (dry_run)
113 {
114 if (strategy_name)
115 pg_log_debug("would copy \"%s\" to \"%s\" using strategy %s",
116 src, dst, strategy_name);
117 else
118 pg_log_debug("would copy \"%s\" to \"%s\"",
119 src, dst);
120 }
121 else
122 {
123 if (strategy_name)
124 pg_log_debug("copying \"%s\" to \"%s\" using strategy %s",
125 src, dst, strategy_name);
126 else if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
127 pg_log_debug("copying \"%s\" to \"%s\"",
128 src, dst);
129 else
130 pg_log_debug("copying \"%s\" to \"%s\" and checksumming with %s",
131 src, dst, pg_checksum_type_name(checksum_ctx->type));
132
133 strategy_implementation(src, dst, checksum_ctx);
134 }
135}
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:174
static void copy_file_clone(const char *src, const char *dest, pg_checksum_context *checksum_ctx)
Definition: copy_file.c:227
static void copy_file_link(const char *src, const char *dest, pg_checksum_context *checksum_ctx)
Definition: copy_file.c:329
static void copy_file_by_range(const char *src, const char *dest, pg_checksum_context *checksum_ctx)
Definition: copy_file.c:273
@ COPY_METHOD_CLONE
Definition: copy_file.h:21
@ COPY_METHOD_LINK
Definition: copy_file.h:27
@ COPY_METHOD_COPY
Definition: copy_file.h:22
@ COPY_METHOD_COPY_FILE_RANGE
Definition: copy_file.h:23
#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_file_link(), COPY_METHOD_CLONE, COPY_METHOD_COPY, COPY_METHOD_COPY_FILE_RANGE, COPY_METHOD_LINK, 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 174 of file copy_file.c.

176{
177 int src_fd;
178 int dest_fd;
179 uint8 *buffer;
180 const int buffer_size = 50 * BLCKSZ;
181 ssize_t rb;
182 unsigned offset = 0;
183
184 if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
185 pg_fatal("could not open file \"%s\": %m", src);
186
187 if ((dest_fd = open(dst, O_WRONLY | O_CREAT | O_EXCL | PG_BINARY,
189 pg_fatal("could not open file \"%s\": %m", dst);
190
191 buffer = pg_malloc(buffer_size);
192
193 while ((rb = read(src_fd, buffer, buffer_size)) > 0)
194 {
195 ssize_t wb;
196
197 if ((wb = write(dest_fd, buffer, rb)) != rb)
198 {
199 if (wb < 0)
200 pg_fatal("could not write to file \"%s\": %m", dst);
201 else
202 pg_fatal("could not write to file \"%s\", offset %u: wrote %d of %d",
203 dst, offset, (int) wb, (int) rb);
204 }
205
206 if (pg_checksum_update(checksum_ctx, buffer, rb) < 0)
207 pg_fatal("could not update checksum of file \"%s\"", dst);
208
209 offset += rb;
210 }
211
212 if (rb < 0)
213 pg_fatal("could not read from file \"%s\": %m", dst);
214
215 pg_free(buffer);
216 close(src_fd);
217 close(dest_fd);
218}
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 273 of file copy_file.c.

275{
276#if defined(HAVE_COPY_FILE_RANGE)
277 int src_fd;
278 int dest_fd;
279 ssize_t nbytes;
280
281 if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
282 pg_fatal("could not open file \"%s\": %m", src);
283
284 if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
286 pg_fatal("could not create file \"%s\": %m", dest);
287
288 do
289 {
290 nbytes = copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0);
291 if (nbytes < 0)
292 pg_fatal("error while copying file range from \"%s\" to \"%s\": %m",
293 src, dest);
294 } while (nbytes > 0);
295
296 close(src_fd);
297 close(dest_fd);
298#else
299 pg_fatal("copy_file_range not supported on this platform");
300#endif
301
302 /* if needed, calculate checksum of the file */
303 checksum_file(src, checksum_ctx);
304}
static void checksum_file(const char *src, pg_checksum_context *checksum_ctx)
Definition: copy_file.c:141

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 227 of file copy_file.c.

229{
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)
234 {
235 int src_fd;
236 int dest_fd;
237
238 if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
239 pg_fatal("could not open file \"%s\": %m", src);
240
241 if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
243 pg_fatal("could not create file \"%s\": %m", dest);
244
245 if (ioctl(dest_fd, FICLONE, src_fd) < 0)
246 {
247 int save_errno = errno;
248
249 unlink(dest);
250
251 pg_fatal("error while cloning file \"%s\" to \"%s\": %s",
252 src, dest, strerror(save_errno));
253 }
254
255 close(src_fd);
256 close(dest_fd);
257 }
258#else
259 pg_fatal("file cloning not supported on this platform");
260#endif
261
262 /* if needed, calculate checksum of the file */
263 checksum_file(src, checksum_ctx);
264}
#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().

◆ copy_file_link()

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

Definition at line 329 of file copy_file.c.

331{
332 if (link(src, dest) < 0)
333 pg_fatal("could not create link from \"%s\" to \"%s\": %m",
334 src, dest);
335
336 /* if needed, calculate checksum of the file */
337 checksum_file(src, checksum_ctx);
338}

References checksum_file(), generate_unaccent_rules::dest, link(), and pg_fatal.

Referenced by copy_file().