43#define INCREMENTAL_PREFIX "INCREMENTAL."
44#define INCREMENTAL_PREFIX_LENGTH (sizeof(INCREMENTAL_PREFIX) - 1)
111 char *input_directory,
112 char *output_directory,
115 char **prior_backup_dirs,
132 static struct option long_options[] = {
148 char *last_input_dir;
156 char **prior_backup_dirs;
169 memset(&opt, 0,
sizeof(opt));
176 long_options, &optindex)) != -1)
199 pg_fatal(
"unrecognized checksum algorithm: \"%s\"",
233 pg_fatal(
"no output directory specified");
242#if (defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)) || \
243 (defined(__linux__) && defined(FICLONE))
251 pg_fatal(
"file cloning not supported on this platform");
256#if defined(HAVE_COPY_FILE_RANGE)
259 pg_log_debug(
"would use copy_file_range to copy blocks");
261 pg_log_debug(
"will use copy_file_range to copy blocks");
264 pg_fatal(
"copy_file_range not supported on this platform");
272 n_backups = argc -
optind;
282 n_prior_backups = argc -
optind - 1;
283 prior_backup_dirs = argv +
optind;
292 for (
i = 0;
i < n_backups;
i++)
295 manifests[
i]->system_identifier != system_identifier)
299 controlpath =
psprintf(
"%s/%s", prior_backup_dirs[
i],
"global/pg_control");
301 pg_fatal(
"%s: manifest system identifier is %llu, but control file has %llu",
303 (
unsigned long long) manifests[
i]->system_identifier,
304 (
unsigned long long) system_identifier);
309 last_input_dir = argv[argc - 1];
326 for (ts = tablespaces; ts != NULL; ts = ts->
next)
339 if (manifests[n_prior_backups] == NULL)
340 pg_fatal(
"cannot generate a manifest because no manifest is available for the final input backup");
351 last_backup_label->
cursor = 0;
357 pg_log_debug(
"processing backup directory \"%s\"", last_input_dir);
359 NULL, n_prior_backups, prior_backup_dirs,
360 manifests, mwriter, &opt);
363 for (ts = tablespaces; ts != NULL; ts = ts->
next)
380 pg_log_debug(
"would create symbolic link from \"%s\" to \"%s\"",
384 pg_log_debug(
"creating symbolic link from \"%s\" to \"%s\"",
387 pg_fatal(
"could not create symbolic link from \"%s\" to \"%s\": %m",
399 pg_fatal(
"could not create directory \"%s\": %m",
406 NULL, n_prior_backups, prior_backup_dirs,
407 manifests, mwriter, &opt);
413 manifests[n_prior_backups]->first_wal_range);
450 dst_ptr = dst = tsmap->
old_dir;
451 for (arg_ptr =
arg; *arg_ptr !=
'\0'; arg_ptr++)
454 pg_fatal(
"directory name too long");
456 if (*arg_ptr ==
'\\' && *(arg_ptr + 1) ==
'=')
458 else if (*arg_ptr ==
'=' && (arg_ptr ==
arg || *(arg_ptr - 1) !=
'\\'))
461 pg_fatal(
"multiple \"=\" signs in tablespace mapping");
463 dst = dst_ptr = tsmap->
new_dir;
466 *dst_ptr++ = *arg_ptr;
469 pg_fatal(
"invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"",
arg);
480 pg_fatal(
"old directory is not an absolute path in tablespace mapping: %s",
484 pg_fatal(
"old directory is not an absolute path in tablespace mapping: %s",
510 for (
i = n_backups - 1;
i >= 0; --
i)
522 if ((
fd = open(pathbuf, O_RDONLY, 0)) < 0)
523 pg_fatal(
"could not open file \"%s\": %m", pathbuf);
538 pg_fatal(
"could not close file \"%s\": %m", pathbuf);
542 &previous_tli, &previous_lsn);
552 if (
i > 0 && previous_tli == 0)
553 pg_fatal(
"backup at \"%s\" is a full backup, but only the first backup should be a full backup",
555 if (
i == 0 && previous_tli != 0)
556 pg_fatal(
"backup at \"%s\" is an incremental backup, but the first backup should be a full backup",
558 if (
i < n_backups - 1 && start_tli != check_tli)
559 pg_fatal(
"backup at \"%s\" starts on timeline %u, but expected %u",
560 backup_dirs[
i], start_tli, check_tli);
561 if (
i < n_backups - 1 && start_lsn != check_lsn)
562 pg_fatal(
"backup at \"%s\" starts at LSN %X/%X, but expected %X/%X",
566 check_tli = previous_tli;
567 check_lsn = previous_lsn;
597 uint64 system_identifier = 0;
598 uint32 data_checksum_version = 0;
599 bool data_checksum_mismatch =
false;
602 for (
i = n_backups - 1;
i >= 0; --
i)
608 controlpath =
psprintf(
"%s/%s", backup_dirs[
i],
"global/pg_control");
614 pg_fatal(
"%s: CRC is incorrect", controlpath);
618 pg_fatal(
"%s: unexpected control file version",
622 if (
i == n_backups - 1)
625 pg_fatal(
"%s: expected system identifier %llu, but found %llu",
626 controlpath, (
unsigned long long) system_identifier,
633 if (
i == n_backups - 1)
635 else if (data_checksum_version != 0 &&
637 data_checksum_mismatch =
true;
649 (
unsigned long long) system_identifier);
655 if (data_checksum_mismatch)
658 pg_log_warning_hint(
"Disable, and optionally reenable, checksums on the output directory to avoid failures.");
661 return system_identifier;
675 if (
stat(dir, &st) != 0)
676 pg_fatal(
"could not stat file \"%s\": %m", dir);
699 pg_log_info(
"removing contents of output directory \"%s\"",
702 pg_log_error(
"failed to remove contents of output directory");
730 pg_fatal(
"could not create directory \"%s\": %m", dirname);
735 pg_log_debug(
"using existing directory \"%s\"", dirname);
742 pg_fatal(
"directory \"%s\" exists but is not empty", dirname);
745 pg_fatal(
"could not access directory \"%s\": %m", dirname);
759 printf(
_(
"%s reconstructs full backups from incrementals.\n\n"),
progname);
763 printf(
_(
" -d, --debug generate lots of debugging output\n"));
764 printf(
_(
" -n, --dry-run do not actually do anything\n"));
765 printf(
_(
" -N, --no-sync do not wait for changes to be written safely to disk\n"));
766 printf(
_(
" -o, --output=DIRECTORY output directory\n"));
767 printf(
_(
" -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
768 " relocate tablespace in OLDDIR to NEWDIR\n"));
769 printf(
_(
" --clone clone (reflink) files instead of copying\n"));
770 printf(
_(
" --copy copy files (default)\n"));
771 printf(
_(
" --copy-file-range copy using copy_file_range() system call\n"));
772 printf(
_(
" --manifest-checksums=SHA{224,256,384,512}|CRC32C|NONE\n"
773 " use algorithm for manifest checksums\n"));
774 printf(
_(
" --no-manifest suppress generation of backup manifest\n"));
775 printf(
_(
" --sync-method=METHOD set method for syncing files to disk\n"));
776 printf(
_(
" -V, --version output version information, then exit\n"));
777 printf(
_(
" -?, --help show this help, then exit\n"));
779 printf(
_(
"\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
780 printf(
_(
"%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
795 oid = strtoul(s, &ep, 10);
796 if (errno != 0 || *ep !=
'\0' || oid < 1 || oid >
PG_UINT32_MAX)
824 char *input_directory,
825 char *output_directory,
828 char **prior_backup_dirs,
838 bool is_pg_tblspc =
false;
839 bool is_pg_wal =
false;
840 bool is_incremental_dir =
false;
867 is_incremental_dir =
true;
868 else if (relative_path != NULL)
871 is_pg_wal = (strcmp(relative_path,
"pg_wal") == 0 ||
872 strncmp(relative_path,
"pg_wal/", 7) == 0);
873 is_incremental_dir = strncmp(relative_path,
"base/", 5) == 0 ||
874 strcmp(relative_path,
"global") == 0 ||
893 if (relative_path == NULL)
900 manifest_prefix[0] =
'\0';
919 if (relative_path != NULL)
922 pg_log_debug(
"would create directory \"%s\"", ofulldir);
927 pg_fatal(
"could not create directory \"%s\": %m", ofulldir);
932 if ((dir =
opendir(ifulldir)) == NULL)
933 pg_fatal(
"could not open directory \"%s\": %m", ifulldir);
934 while (errno = 0, (de =
readdir(dir)) != NULL)
941 int checksum_length = 0;
942 uint8 *checksum_payload = NULL;
946 if (strcmp(de->
d_name,
".") == 0 ||
947 strcmp(de->
d_name,
"..") == 0)
976 if (relative_path == NULL)
984 input_directory, output_directory,
986 n_prior_backups, prior_backup_dirs,
987 manifests, mwriter, opt);
1005 if (relative_path == NULL &&
1006 (strcmp(de->
d_name,
"backup_label") == 0 ||
1007 strcmp(de->
d_name,
"backup_manifest") == 0))
1014 if (is_incremental_dir &&
1057 latest_manifest != NULL)
1061 mfile = manifest_files_lookup(latest_manifest->
files,
1071 bmpath =
psprintf(
"%s/%s", input_directory,
1073 pg_log_warning(
"manifest file \"%s\" contains no entry for file \"%s\"",
1074 bmpath, manifest_path);
1089 if (checksum_length != 0)
1096 copy_file(ifullpath, ofullpath, &checksum_ctx,
1113 if (mwriter != NULL)
1130 if (
stat(ofullpath, &sb) < 0)
1131 pg_fatal(
"could not stat file \"%s\": %m", ofullpath);
1136 checksum_type, checksum_length,
1141 if (checksum_payload != NULL)
1142 pfree(checksum_payload);
1179 version = strtoul(
buf.data, &ep, 10);
1180 if (errno != 0 || *ep !=
'\n')
1188 if (version < 10 && *ep ==
'.')
1198 return version * 10000;
1255 if ((dir =
opendir(pg_tblspc)) == NULL)
1256 pg_fatal(
"could not open directory \"%s\": %m", pg_tblspc);
1258 while (errno = 0, (de =
readdir(dir)) != NULL)
1269 if (strcmp(de->
d_name,
".") == 0 || strcmp(de->
d_name,
"..") == 0)
1278 pg_log_debug(
"skipping \"%s\" because the filename is not a legal tablespace OID",
1289 pg_log_debug(
"skipping \"%s\" because it is neither a symbolic link nor a directory",
1307 link_length =
readlink(tblspcdir, link_target,
sizeof(link_target));
1308 if (link_length < 0)
1309 pg_fatal(
"could not read symbolic link \"%s\": %m",
1311 if (link_length >=
sizeof(link_target))
1312 pg_fatal(
"target of symbolic link \"%s\" is too long", tblspcdir);
1313 link_target[link_length] =
'\0';
1315 pg_fatal(
"target of symbolic link \"%s\" is relative", tblspcdir);
1324 for (tsmap = opt->
tsmappings; tsmap != NULL; tsmap = tsmap->
next)
1326 if (strcmp(tsmap->
old_dir, link_target) == 0)
1337 pg_fatal(
"tablespace at \"%s\" has no tablespace mapping",
1353 for (otherts = tslist; otherts != NULL; otherts = otherts->
next)
1355 pg_fatal(
"tablespaces with OIDs %u and %u both point at directory \"%s\"",
1364 pg_fatal(
"could not close directory \"%s\": %m", pg_tblspc);
1402 pg_fatal(
"could not read file \"%s\": read %zd of %lld",
1408 buf->data[
buf->len] =
'\0';
void parse_backup_label(char *filename, StringInfo buf, TimeLineID *start_tli, XLogRecPtr *start_lsn, TimeLineID *previous_tli, XLogRecPtr *previous_lsn)
void write_backup_label(char *output_directory, StringInfo buf, pg_checksum_type checksum_type, manifest_writer *mwriter)
#define PG_TEXTDOMAIN(domain)
#define OidIsValid(objectId)
bool pg_checksum_parse_type(char *name, pg_checksum_type *type)
int pg_checksum_final(pg_checksum_context *context, uint8 *output)
int pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
#define PG_CHECKSUM_MAX_LENGTH
void set_pglocale_pgservice(const char *argv0, const char *app)
ControlFileData * get_controlfile_by_exact_path(const char *ControlFilePath, bool *crc_ok_p)
@ COPY_METHOD_COPY_FILE_RANGE
void copy_file(const char *fromfile, const char *tofile)
struct dirent * readdir(DIR *)
DIR * opendir(const char *)
void * pg_malloc(size_t size)
void * pg_malloc0(size_t size)
void SetDataDirectoryCreatePerm(int dataDirMode)
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
@ DATA_DIR_SYNC_METHOD_FSYNC
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
#define required_argument
manifest_data ** load_backup_manifests(int n_backups, char **backup_directories)
void pg_logging_increase_verbosity(void)
void pg_logging_init(const char *argv0)
#define pg_log_error(...)
#define pg_log_error_hint(...)
#define pg_log_warning_hint(...)
#define pg_log_debug(...)
void pfree(void *pointer)
void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
bool parse_sync_method(const char *optarg, DataDirSyncMethod *sync_method)
static cb_tablespace * scan_for_existing_tablespaces(char *pathname, cb_options *opt)
int main(int argc, char *argv[])
struct cb_cleanup_dir cb_cleanup_dir
static void remember_to_cleanup_directory(char *target_path, bool rmtopdir)
static void help(const char *progname)
static void process_directory_recursively(Oid tsoid, char *input_directory, char *output_directory, char *relative_path, int n_prior_backups, char **prior_backup_dirs, manifest_data **manifests, manifest_writer *mwriter, cb_options *opt)
static void create_output_directory(char *dirname, cb_options *opt)
static void check_input_dir_permissions(char *dir)
static uint64 check_control_files(int n_backups, char **backup_dirs)
static cb_cleanup_dir * cleanup_dir_list
struct cb_tablespace cb_tablespace
#define INCREMENTAL_PREFIX_LENGTH
static void cleanup_directories_atexit(void)
static StringInfo check_backup_label_files(int n_backups, char **backup_dirs)
static void add_tablespace_mapping(cb_options *opt, char *arg)
#define INCREMENTAL_PREFIX
struct cb_tablespace_mapping cb_tablespace_mapping
static void slurp_file(int fd, char *filename, StringInfo buf, int maxlen)
struct cb_options cb_options
static bool parse_oid(char *s, Oid *result)
static int read_pg_version_file(char *directory)
static void reset_directory_cleanup_list(void)
#define PG_CONTROL_VERSION
PGDLLIMPORT char * optarg
#define pg_log_warning(...)
int pg_mkdir_p(char *path, int omode)
#define is_absolute_path(filename)
void canonicalize_path(char *path)
int pg_check_dir(const char *dir)
const char * get_progname(const char *argv0)
size_t strlcpy(char *dst, const char *src, size_t siz)
static int fd(const char *x, int i)
char * psprintf(const char *fmt,...)
void reconstruct_from_incremental_file(char *input_filename, char *output_filename, char *relative_path, char *bare_file_name, int n_prior_backups, char **prior_backup_dirs, manifest_data **manifests, char *manifest_path, pg_checksum_type checksum_type, int *checksum_length, uint8 **checksum_payload, CopyMethod copy_method, bool debug, bool dry_run)
#define PG_TBLSPC_DIR_SLASH
bool rmtree(const char *path, bool rmtopdir)
void destroyStringInfo(StringInfo str)
StringInfo makeStringInfo(void)
void resetStringInfo(StringInfo str)
void enlargeStringInfo(StringInfo str, int needed)
void initStringInfo(StringInfo str)
uint32 pg_control_version
uint32 data_checksum_version
struct cb_cleanup_dir * next
cb_tablespace_mapping * tsmappings
DataDirSyncMethod sync_method
pg_checksum_type manifest_checksums
struct cb_tablespace_mapping * next
struct cb_tablespace * next
manifest_files_hash * files
pg_checksum_type checksum_type
#define symlink(oldpath, newpath)
#define readlink(path, buf, size)
manifest_writer * create_manifest_writer(char *directory, uint64 system_identifier)
void add_file_to_manifest(manifest_writer *mwriter, const char *manifest_path, uint64 size, time_t mtime, pg_checksum_type checksum_type, int checksum_length, uint8 *checksum_payload)
void finalize_manifest(manifest_writer *mwriter, manifest_wal_range *first_wal_range)
#define LSN_FORMAT_ARGS(lsn)
#define InvalidXLogRecPtr
static const char * directory