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 *dst, pg_checksum_context *checksum_ctx)
 
static void copy_file_by_range (const char *src, const char *dst, 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 123 of file copy_file.c.

124 {
125  int src_fd;
126  uint8 *buffer;
127  const int buffer_size = 50 * BLCKSZ;
128  ssize_t rb;
129 
130  /* bail out if no checksum needed */
131  if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
132  return;
133 
134  if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
135  pg_fatal("could not open file \"%s\": %m", src);
136 
137  buffer = pg_malloc(buffer_size);
138 
139  while ((rb = read(src_fd, buffer, buffer_size)) > 0)
140  {
141  if (pg_checksum_update(checksum_ctx, buffer, rb) < 0)
142  pg_fatal("could not update checksum of file \"%s\"", src);
143  }
144 
145  if (rb < 0)
146  pg_fatal("could not read file \"%s\": %m", src);
147 
148  pg_free(buffer);
149  close(src_fd);
150 }
#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 45 of file copy_file.c.

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

158 {
159  int src_fd;
160  int dest_fd;
161  uint8 *buffer;
162  const int buffer_size = 50 * BLCKSZ;
163  ssize_t rb;
164  unsigned offset = 0;
165 
166  if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
167  pg_fatal("could not open file \"%s\": %m", src);
168 
169  if ((dest_fd = open(dst, O_WRONLY | O_CREAT | O_EXCL | PG_BINARY,
170  pg_file_create_mode)) < 0)
171  pg_fatal("could not open file \"%s\": %m", dst);
172 
173  buffer = pg_malloc(buffer_size);
174 
175  while ((rb = read(src_fd, buffer, buffer_size)) > 0)
176  {
177  ssize_t wb;
178 
179  if ((wb = write(dest_fd, buffer, rb)) != rb)
180  {
181  if (wb < 0)
182  pg_fatal("could not write file \"%s\": %m", dst);
183  else
184  pg_fatal("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
185  dst, (int) wb, (int) rb, offset);
186  }
187 
188  if (pg_checksum_update(checksum_ctx, buffer, rb) < 0)
189  pg_fatal("could not update checksum of file \"%s\"", dst);
190 
191  offset += rb;
192  }
193 
194  if (rb < 0)
195  pg_fatal("could not read file \"%s\": %m", dst);
196 
197  pg_free(buffer);
198  close(src_fd);
199  close(dest_fd);
200 }
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 *  dst,
pg_checksum_context checksum_ctx 
)
static

Definition at line 249 of file copy_file.c.

251 {
252 #if defined(HAVE_COPY_FILE_RANGE)
253  int src_fd;
254  int dest_fd;
255  ssize_t nbytes;
256 
257  if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
258  pg_fatal("could not open file \"%s\": %m", src);
259 
260  if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
261  pg_file_create_mode)) < 0)
262  pg_fatal("could not create file \"%s\": %m", dest);
263 
264  do
265  {
266  nbytes = copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0);
267  if (nbytes < 0)
268  pg_fatal("error while copying file range from \"%s\" to \"%s\": %m",
269  src, dest);
270  } while (nbytes > 0);
271 
272  close(src_fd);
273  close(dest_fd);
274 #else
275  pg_fatal("copy_file_range not supported on this platform");
276 #endif
277 
278  /* if needed, calculate checksum of the file */
279  checksum_file(src, checksum_ctx);
280 }
static void checksum_file(const char *src, pg_checksum_context *checksum_ctx)
Definition: copy_file.c:123

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 *  dst,
pg_checksum_context checksum_ctx 
)
static

Definition at line 209 of file copy_file.c.

211 {
212 #if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
213  if (copyfile(src, dest, NULL, COPYFILE_CLONE_FORCE) < 0)
214  pg_fatal("error while cloning file \"%s\" to \"%s\": %m", src, dest);
215 #elif defined(__linux__) && defined(FICLONE)
216  {
217  if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
218  pg_fatal("could not open file \"%s\": %m", src);
219 
220  if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
221  pg_file_create_mode)) < 0)
222  pg_fatal("could not create file \"%s\": %m", dest);
223 
224  if (ioctl(dest_fd, FICLONE, src_fd) < 0)
225  {
226  int save_errno = errno;
227 
228  unlink(dest);
229 
230  pg_fatal("error while cloning file \"%s\" to \"%s\": %s",
231  src, dest);
232  }
233  }
234 #else
235  pg_fatal("file cloning not supported on this platform");
236 #endif
237 
238  /* if needed, calculate checksum of the file */
239  checksum_file(src, checksum_ctx);
240 }

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

Referenced by copy_file().