|
18 | 18 |
|
19 | 19 | #include <sys/stat.h> |
20 | 20 | #include <fcntl.h> |
| 21 | +#ifdef HAVE_COPYFILE |
| 22 | +#include <copyfile.h> |
| 23 | +#endif |
| 24 | +#ifdef __linux__ |
| 25 | +#include <sys/ioctl.h> |
| 26 | +#include <linux/fs.h> |
| 27 | +#endif |
21 | 28 |
|
22 | 29 |
|
23 | 30 | #ifdef WIN32 |
24 | 31 | static int win32_pghardlink(const char *src, const char *dst); |
25 | 32 | #endif |
26 | 33 |
|
27 | 34 |
|
| 35 | +/* |
| 36 | + * cloneFile() |
| 37 | + * |
| 38 | + * Clones/reflinks a relation file from src to dst. |
| 39 | + * |
| 40 | + * schemaName/relName are relation's SQL name (used for error messages only). |
| 41 | + */ |
| 42 | +void |
| 43 | +cloneFile(const char *src, const char *dst, |
| 44 | + const char *schemaName, const char *relName) |
| 45 | +{ |
| 46 | +#if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE) |
| 47 | + if (copyfile(src, dst, NULL, COPYFILE_CLONE_FORCE) < 0) |
| 48 | + pg_fatal("error while cloning relation \"%s.%s\" (\"%s\" to \"%s\"): %s\n", |
| 49 | + schemaName, relName, src, dst, strerror(errno)); |
| 50 | +#elif defined(__linux__) && defined(FICLONE) |
| 51 | + int src_fd; |
| 52 | + int dest_fd; |
| 53 | + |
| 54 | + if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) |
| 55 | + pg_fatal("error while cloning relation \"%s.%s\": could not open file \"%s\": %s\n", |
| 56 | + schemaName, relName, src, strerror(errno)); |
| 57 | + |
| 58 | + if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, |
| 59 | + pg_file_create_mode)) < 0) |
| 60 | + pg_fatal("error while cloning relation \"%s.%s\": could not create file \"%s\": %s\n", |
| 61 | + schemaName, relName, dst, strerror(errno)); |
| 62 | + |
| 63 | + if (ioctl(dest_fd, FICLONE, src_fd) < 0) |
| 64 | + { |
| 65 | + unlink(dst); |
| 66 | + pg_fatal("error while cloning relation \"%s.%s\" (\"%s\" to \"%s\"): %s\n", |
| 67 | + schemaName, relName, src, dst, strerror(errno)); |
| 68 | + } |
| 69 | + |
| 70 | + close(src_fd); |
| 71 | + close(dest_fd); |
| 72 | +#endif |
| 73 | +} |
| 74 | + |
| 75 | + |
28 | 76 | /* |
29 | 77 | * copyFile() |
30 | 78 | * |
@@ -270,6 +318,48 @@ rewriteVisibilityMap(const char *fromfile, const char *tofile, |
270 | 318 | close(src_fd); |
271 | 319 | } |
272 | 320 |
|
| 321 | +void |
| 322 | +check_file_clone(void) |
| 323 | +{ |
| 324 | + char existing_file[MAXPGPATH]; |
| 325 | + char new_link_file[MAXPGPATH]; |
| 326 | + |
| 327 | + snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata); |
| 328 | + snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.clonetest", new_cluster.pgdata); |
| 329 | + unlink(new_link_file); /* might fail */ |
| 330 | + |
| 331 | +#if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE) |
| 332 | + if (copyfile(existing_file, new_link_file, NULL, COPYFILE_CLONE_FORCE) < 0) |
| 333 | + pg_fatal("could not clone file between old and new data directories: %s\n", |
| 334 | + strerror(errno)); |
| 335 | +#elif defined(__linux__) && defined(FICLONE) |
| 336 | + { |
| 337 | + int src_fd; |
| 338 | + int dest_fd; |
| 339 | + |
| 340 | + if ((src_fd = open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0) |
| 341 | + pg_fatal("could not open file \"%s\": %s\n", |
| 342 | + existing_file, strerror(errno)); |
| 343 | + |
| 344 | + if ((dest_fd = open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, |
| 345 | + pg_file_create_mode)) < 0) |
| 346 | + pg_fatal("could not create file \"%s\": %s\n", |
| 347 | + new_link_file, strerror(errno)); |
| 348 | + |
| 349 | + if (ioctl(dest_fd, FICLONE, src_fd) < 0) |
| 350 | + pg_fatal("could not clone file between old and new data directories: %s\n", |
| 351 | + strerror(errno)); |
| 352 | + |
| 353 | + close(src_fd); |
| 354 | + close(dest_fd); |
| 355 | + } |
| 356 | +#else |
| 357 | + pg_fatal("file cloning not supported on this platform\n"); |
| 358 | +#endif |
| 359 | + |
| 360 | + unlink(new_link_file); |
| 361 | +} |
| 362 | + |
273 | 363 | void |
274 | 364 | check_hard_link(void) |
275 | 365 | { |
|
0 commit comments