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 }
#define PG_BINARY
Definition: c.h:1273
unsigned char uint8
Definition: c.h:504
int pg_checksum_update(pg_checksum_context *context, const uint8 *input, size_t len)
@ CHECKSUM_TYPE_NONE
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#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  {
78  case COPY_METHOD_CLONE:
79  strategy_name = "clone";
80  strategy_implementation = copy_file_clone;
81  break;
82  case COPY_METHOD_COPY:
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:23
@ COPY_METHOD_COPY
Definition: copy_file.h:24
@ COPY_METHOD_COPY_FILE_RANGE
Definition: copy_file.h:25
#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,
174  pg_file_create_mode)) < 0)
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,
271  pg_file_create_mode)) < 0)
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,
228  pg_file_create_mode)) < 0)
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:251

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

Referenced by copy_file().