57 unsigned block_length,
93 char **prior_backup_dirs,
98 uint8 **checksum_payload,
104 rfile *latest_source = NULL;
107 unsigned block_length;
109 unsigned sidx = n_prior_backups;
110 bool full_copy_possible =
true;
111 int copy_source_index = -1;
112 rfile *copy_source = NULL;
116 Assert(relative_path[0] !=
'\0');
117 Assert(relative_path[strlen(relative_path) - 1] ==
'/');
130 source[n_prior_backups] = latest_source;
139 offsetmap =
pg_malloc0(
sizeof(off_t) * block_length);
155 sourcemap[
b] = latest_source;
162 full_copy_possible =
false;
183 prior_backup_dirs[sidx], relative_path, bare_file_name);
184 if ((s =
make_rfile(source_filename,
true)) == NULL)
187 prior_backup_dirs[sidx], relative_path, bare_file_name);
227 blocklength = sb.
st_size / BLCKSZ;
230 if (sourcemap[
b] == NULL &&
b < blocklength)
233 offsetmap[
b] =
b * BLCKSZ;
242 if (full_copy_possible)
248 expected_length *= BLCKSZ;
252 copy_source_index = sidx;
268 if (b < latest_source->truncation_block_length &&
269 sourcemap[
b] == NULL)
279 full_copy_possible =
false;
289 if (copy_source_index >= 0 && manifests[copy_source_index] != NULL &&
294 mfile = manifest_files_lookup(manifests[copy_source_index]->files,
298 char *path =
psprintf(
"%s/backup_manifest",
299 prior_backup_dirs[copy_source_index]);
305 pg_log_warning(
"manifest file \"%s\" contains no entry for file \"%s\"",
313 *checksum_payload =
pg_malloc(*checksum_length);
334 if (copy_source != NULL)
336 &checksum_ctx, copy_method,
dry_run);
337 else if (sidx == 0 &&
source[0]->header_length != 0)
339 pg_fatal(
"full backup contains unexpected incremental file \"%s\"",
345 block_length, sourcemap, offsetmap,
346 &checksum_ctx, copy_method,
362 for (
i = 0;
i <= n_prior_backups; ++
i)
387 for (
i = 0;
i < n_source; ++
i)
423 pg_fatal(
"file \"%s\" is too short: expected %llu, found %llu",
426 (
unsigned long long) sb.
st_size);
465 pg_fatal(
"file \"%s\" has bad incremental magic number (0x%x, expected 0x%x)",
471 pg_fatal(
"file \"%s\" has block count %u in excess of segment size %u",
478 pg_fatal(
"file \"%s\" has truncation block length %u in excess of segment size %u",
518 if (missing_ok && errno == ENOENT)
535 int rb =
read(rf->
fd, buffer, length);
542 pg_fatal(
"could not read file \"%s\": read %d of %u",
553 unsigned block_length,
563 unsigned zero_blocks = 0;
569 unsigned start_of_range = 0;
570 unsigned current_block = 0;
574 pg_log_debug(
"would reconstruct \"%s\" (%u blocks, checksum %s)",
578 pg_log_debug(
"reconstructing \"%s\" (%u blocks, checksum %s)",
584 while (current_block < block_length)
586 rfile *s = sourcemap[current_block];
589 if (current_block + 1 < block_length &&
590 s == sourcemap[current_block + 1])
599 if (current_block == start_of_range)
603 start_of_range, current_block);
607 if (current_block == start_of_range)
610 (
uint64) offsetmap[current_block]);
613 start_of_range, current_block,
615 (
uint64) offsetmap[current_block]);
619 start_of_range = ++current_block;
622 if (current_block == block_length || debug_buf.
len > 1024)
641 for (
i = 0;
i < block_length; ++
i)
643 uint8 buffer[BLCKSZ];
653 offsetmap[
i] + BLCKSZ);
667 memset(buffer, 0, BLCKSZ);
688 #if defined(HAVE_COPY_FILE_RANGE)
690 off_t off = offsetmap[
i];
701 wb = copy_file_range(s->
fd, &off, wfd, NULL, BLCKSZ - nwritten, 0);
704 pg_fatal(
"error while copying file range from \"%s\" to \"%s\": %m",
709 }
while (BLCKSZ > nwritten);
721 pg_fatal(
"could not update checksum of file \"%s\"",
724 pg_fatal(
"copy_file_range not supported on this platform");
733 pg_log_debug(
"would have zero-filled %u blocks", zero_blocks);
739 if (wfd >= 0 &&
close(wfd) != 0)
756 if ((wb =
write(
fd, buffer, BLCKSZ)) != BLCKSZ)
761 pg_fatal(
"could not write file \"%s\": wrote %d of %d",
767 pg_fatal(
"could not update checksum of file \"%s\"",
786 pg_fatal(
"could not read from file \"%s\", offset %llu: read %d of %d",
787 s->
filename, (
unsigned long long) off, rb, BLCKSZ);
#define INCREMENTAL_MAGIC
#define Assert(condition)
char * pg_checksum_type_name(pg_checksum_type type)
int pg_checksum_final(pg_checksum_context *context, uint8 *output)
int pg_checksum_update(pg_checksum_context *context, const uint8 *input, size_t len)
int pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
#define PG_CHECKSUM_MAX_LENGTH
@ COPY_METHOD_COPY_FILE_RANGE
void copy_file(const char *fromfile, const char *tofile)
void * pg_malloc0(size_t size)
void * pg_malloc(size_t size)
if(TABLE==NULL||TABLE_index==NULL)
#define pg_log_debug(...)
char * pstrdup(const char *in)
void pfree(void *pointer)
static rewind_source * source
#define pg_log_warning(...)
static int fd(const char *x, int i)
char * psprintf(const char *fmt,...)
static rfile * make_rfile(char *filename, bool missing_ok)
static rfile * make_incremental_rfile(char *filename)
static void debug_reconstruction(int n_source, rfile **sources, bool dry_run)
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)
static void read_block(rfile *s, off_t off, uint8 *buffer)
static void read_bytes(rfile *rf, void *buffer, unsigned length)
static void write_reconstructed_file(char *input_filename, char *output_filename, unsigned block_length, rfile **sourcemap, off_t *offsetmap, pg_checksum_context *checksum_ctx, CopyMethod copy_method, bool debug, bool dry_run)
static unsigned find_reconstructed_block_length(rfile *s)
static void write_block(int fd, char *output_filename, uint8 *buffer, pg_checksum_context *checksum_ctx)
void resetStringInfo(StringInfo str)
void appendStringInfo(StringInfo str, const char *fmt,...)
void initStringInfo(StringInfo str)
pg_checksum_type checksum_type
off_t highest_offset_read
BlockNumber * relative_block_numbers
unsigned truncation_block_length