Skip to content

Commit 0249fb4

Browse files
committed
Merge commit '94540661566677a456e927050664b7e03db601d0' into PGPRO9_6
Conflicts: contrib/pg_probackup/pgut/getopt_long.c
2 parents f80dca2 + 9454066 commit 0249fb4

File tree

14 files changed

+733
-413
lines changed

14 files changed

+733
-413
lines changed

contrib/pg_probackup/backup.c

Lines changed: 70 additions & 116 deletions
Large diffs are not rendered by default.

contrib/pg_probackup/catalog.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ pgBackupCreateDir(pgBackup *backup)
242242
char *subdirs[] = { DATABASE_DIR, NULL };
243243

244244
pgBackupGetPath(backup, path, lengthof(path), NULL);
245+
246+
if (!dir_is_empty(path))
247+
elog(ERROR, "backup destination is not empty \"%s\"", path);
248+
245249
dir_create_dir(path, DIR_PERMISSION);
246250

247251
/* create directories for actual backup files */
@@ -525,6 +529,8 @@ pgBackupGetPath(const pgBackup *backup, char *path, size_t len, const char *subd
525529
else
526530
snprintf(path, len, "%s/%s/%s", backup_path, BACKUPS_DIR, datetime);
527531
free(datetime);
532+
533+
make_native_path(path);
528534
}
529535

530536
void

contrib/pg_probackup/dir.c

Lines changed: 172 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ const char *pgdata_exclude_dir[] =
2525
"pg_xlog",
2626
"pg_stat_tmp",
2727
"pgsql_tmp",
28-
NULL, /* arclog_path will be set later */
2928
NULL, /* pg_log will be set later */
3029
NULL
3130
};
@@ -41,12 +40,18 @@ static char *pgdata_exclude_files[] =
4140
pgFile *pgFileNew(const char *path, bool omit_symlink);
4241
static int BlackListCompare(const void *str1, const void *str2);
4342

44-
/* create directory, also create parent directories if necessary */
43+
static void dir_list_file_internal(parray *files, const char *root,
44+
bool exclude, bool omit_symlink,
45+
bool add_root, parray *black_list);
46+
47+
/*
48+
* Create directory, also create parent directories if necessary.
49+
*/
4550
int
4651
dir_create_dir(const char *dir, mode_t mode)
4752
{
48-
char copy[MAXPGPATH];
49-
char parent[MAXPGPATH];
53+
char copy[MAXPGPATH];
54+
char parent[MAXPGPATH];
5055

5156
strncpy(copy, dir, MAXPGPATH);
5257
strncpy(parent, dirname(copy), MAXPGPATH);
@@ -60,8 +65,7 @@ dir_create_dir(const char *dir, mode_t mode)
6065
{
6166
if (errno == EEXIST) /* already exist */
6267
return 0;
63-
elog(ERROR, "cannot create directory \"%s\": %s", dir,
64-
strerror(errno));
68+
elog(ERROR, "cannot create directory \"%s\": %s", dir, strerror(errno));
6569
}
6670

6771
return 0;
@@ -295,7 +299,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool omit_symlink,
295299
parray_qsort(files, pgFileComparePath);
296300
}
297301

298-
void
302+
static void
299303
dir_list_file_internal(parray *files, const char *root, bool exclude,
300304
bool omit_symlink, bool add_root, parray *black_list)
301305
{
@@ -327,11 +331,7 @@ dir_list_file_internal(parray *files, const char *root, bool exclude,
327331
else
328332
file_name++;
329333

330-
/*
331-
* If the item in the exclude list starts with '/', compare to the
332-
* absolute path of the directory. Otherwise compare to the directory
333-
* name portion.
334-
*/
334+
/* Check if we need to exclude file by name */
335335
for (i = 0; pgdata_exclude_files[i]; i++)
336336
if (strcmp(file_name, pgdata_exclude_files[i]) == 0)
337337
/* Skip */
@@ -416,13 +416,10 @@ dir_list_file_internal(parray *files, const char *root, bool exclude,
416416
break;
417417
}
418418
}
419-
else
419+
else if (strcmp(dirname, pgdata_exclude_dir[i]) == 0)
420420
{
421-
if (strcmp(dirname, pgdata_exclude_dir[i]) == 0)
422-
{
423-
skip = true;
424-
break;
425-
}
421+
skip = true;
422+
break;
426423
}
427424
}
428425
if (skip)
@@ -468,74 +465,159 @@ dir_list_file_internal(parray *files, const char *root, bool exclude,
468465
}
469466
}
470467

471-
/* print mkdirs.sh */
468+
/*
469+
* List data directories excluding directories from
470+
* pgdata_exclude_dir array.
471+
*
472+
* **is_root** is a little bit hack. We exclude only first level of directories
473+
* and on the first level we check all files and directories.
474+
*/
472475
void
473-
dir_print_mkdirs_sh(FILE *out, const parray *files, const char *root)
476+
list_data_directories(parray *files, const char *path, bool is_root,
477+
bool exclude)
474478
{
475-
int i;
476-
477-
for (i = 0; i < parray_num(files); i++)
479+
DIR *dir;
480+
struct dirent *dent;
481+
int prev_errno;
482+
bool has_child_dirs = false;
483+
484+
/* open directory and list contents */
485+
dir = opendir(path);
486+
if (dir == NULL)
487+
elog(ERROR, "cannot open directory \"%s\": %s", path, strerror(errno));
488+
489+
errno = 0;
490+
while ((dent = readdir(dir)))
478491
{
479-
pgFile *file = (pgFile *) parray_get(files, i);
480-
if (S_ISDIR(file->mode))
492+
char child[MAXPGPATH];
493+
bool skip = false;
494+
struct stat st;
495+
496+
/* skip entries point current dir or parent dir */
497+
if (strcmp(dent->d_name, ".") == 0 ||
498+
strcmp(dent->d_name, "..") == 0)
499+
continue;
500+
501+
join_path_components(child, path, dent->d_name);
502+
503+
if (lstat(child, &st) == -1)
504+
elog(ERROR, "cannot stat file \"%s\": %s", child, strerror(errno));
505+
506+
if (!S_ISDIR(st.st_mode))
481507
{
482-
if (strstr(file->path, root) == file->path &&
483-
*(file->path + strlen(root)) == '/')
484-
{
485-
fprintf(out, "mkdir -m 700 -p %s\n", file->path + strlen(root) + 1);
486-
}
508+
/* Stop reading the directory if we met file */
509+
if (!is_root)
510+
break;
487511
else
512+
continue;
513+
}
514+
515+
/* Check for exclude for the first level of listing */
516+
if (is_root && exclude)
517+
{
518+
int i;
519+
520+
for (i = 0; pgdata_exclude_dir[i]; i++)
488521
{
489-
fprintf(out, "mkdir -m 700 -p %s\n", file->path);
522+
if (strcmp(dent->d_name, pgdata_exclude_dir[i]) == 0)
523+
{
524+
skip = true;
525+
break;
526+
}
490527
}
491528
}
492-
}
529+
if (skip)
530+
continue;
493531

494-
fprintf(out, "\n");
532+
has_child_dirs = true;
533+
list_data_directories(files, child, false, exclude);
534+
}
495535

496-
for (i = 0; i < parray_num(files); i++)
536+
/* List only full and last directories */
537+
if (!is_root && !has_child_dirs)
497538
{
498-
pgFile *file = (pgFile *) parray_get(files, i);
499-
if (S_ISLNK(file->mode))
500-
{
501-
fprintf(out, "rm -f %s\n", file->path + strlen(root) + 1);
502-
fprintf(out, "ln -s %s %s\n", file->linked, file->path + strlen(root) + 1);
503-
}
539+
pgFile *dir;
540+
541+
dir = pgFileNew(path, false);
542+
parray_append(files, dir);
504543
}
544+
545+
prev_errno = errno;
546+
closedir(dir);
547+
548+
if (prev_errno && prev_errno != ENOENT)
549+
elog(ERROR, "cannot read directory \"%s\": %s",
550+
path, strerror(prev_errno));
505551
}
506552

507-
/* print file list */
553+
/*
554+
* Read names of symbolik names of tablespaces with links to directories from
555+
* tablespace_map or tablespace_map.txt.
556+
*/
508557
void
509-
dir_print_file_list(FILE *out, const parray *files, const char *root, const char *prefix)
558+
read_tablespace_map(parray *files, const char *backup_dir)
510559
{
511-
int i;
512-
int root_len = 0;
560+
FILE *fp;
561+
char db_path[MAXPGPATH],
562+
map_path[MAXPGPATH];
563+
char buf[MAXPGPATH * 2];
513564

514-
/* calculate length of root directory portion */
515-
if (root)
565+
join_path_components(db_path, backup_dir, DATABASE_DIR);
566+
join_path_components(map_path, db_path, "tablespace_map");
567+
568+
/* Exit if database/tablespace_map don't exists */
569+
if (!fileExists(map_path))
516570
{
517-
root_len = strlen(root);
518-
if (root[root_len - 1] != '/')
519-
root_len++;
571+
elog(LOG, "there is no file tablespace_map");
572+
return;
520573
}
521574

575+
fp = fopen(map_path, "rt");
576+
if (fp == NULL)
577+
elog(ERROR, "cannot open \"%s\": %s", map_path, strerror(errno));
578+
579+
while (fgets(buf, lengthof(buf), fp))
580+
{
581+
char link_name[MAXPGPATH],
582+
path[MAXPGPATH];
583+
pgFile *file;
584+
585+
if (sscanf(buf, "%s %s", link_name, path) != 2)
586+
elog(ERROR, "invalid format found in \"%s\"", map_path);
587+
588+
file = pgut_new(pgFile);
589+
memset(file, 0, sizeof(pgFile));
590+
591+
file->path = pgut_malloc(strlen(link_name) + 1);
592+
strcpy(file->path, link_name);
593+
594+
file->linked = pgut_malloc(strlen(path) + 1);
595+
strcpy(file->linked, path);
596+
597+
parray_append(files, file);
598+
}
599+
600+
fclose(fp);
601+
}
602+
603+
/*
604+
* Print file list.
605+
*/
606+
void
607+
print_file_list(FILE *out, const parray *files, const char *root)
608+
{
609+
size_t i;
610+
522611
/* print each file in the list */
523612
for (i = 0; i < parray_num(files); i++)
524613
{
525-
pgFile *file = (pgFile *)parray_get(files, i);
526-
char path[MAXPGPATH];
527-
char *ptr = file->path;
528-
char type;
614+
pgFile *file = (pgFile *) parray_get(files, i);
615+
char *path = file->path;
616+
char type;
529617

530618
/* omit root directory portion */
531-
if (root && strstr(ptr, root) == ptr)
532-
ptr = JoinPathEnd(ptr, root);
533-
534-
/* append prefix if not NULL */
535-
if (prefix)
536-
join_path_components(path, prefix, ptr);
537-
else
538-
strcpy(path, ptr);
619+
if (root && strstr(path, root) == path)
620+
path = JoinPathEnd(path, root);
539621

540622
if (S_ISREG(file->mode) && file->is_datafile)
541623
type = 'F';
@@ -556,7 +638,8 @@ dir_print_file_list(FILE *out, const parray *files, const char *root, const char
556638
fprintf(out, " %s", file->linked);
557639
else
558640
{
559-
char timestamp[20];
641+
char timestamp[20];
642+
560643
time2iso(timestamp, 20, file->mtime);
561644
fprintf(out, " %s", timestamp);
562645
}
@@ -683,45 +766,39 @@ dir_read_file_list(const char *root, const char *file_txt)
683766
}
684767

685768
/*
686-
* Copy contents of directory from_root into to_root.
769+
* Check if directory empty.
687770
*/
688-
void
689-
dir_copy_files(const char *from_root, const char *to_root)
771+
bool
772+
dir_is_empty(const char *path)
690773
{
691-
size_t i;
692-
parray *files = parray_new();
774+
DIR *dir;
775+
struct dirent *dir_ent;
693776

694-
/* don't copy root directory */
695-
dir_list_file(files, from_root, false, true, false);
696-
697-
for (i = 0; i < parray_num(files); i++)
777+
dir = opendir(path);
778+
if (dir == NULL)
698779
{
699-
pgFile *file = (pgFile *) parray_get(files, i);
700-
701-
if (S_ISDIR(file->mode))
702-
{
703-
char to_path[MAXPGPATH];
780+
/* Directory in path doesn't exist */
781+
if (errno == ENOENT)
782+
return true;
783+
elog(ERROR, "cannot open directory \"%s\": %s", path, strerror(errno));
784+
}
704785

705-
join_path_components(to_path, to_root,
706-
file->path + strlen(from_root) + 1);
786+
errno = 0;
787+
while ((dir_ent = readdir(dir)))
788+
{
789+
/* Skip entries point current dir or parent dir */
790+
if (strcmp(dir_ent->d_name, ".") == 0 ||
791+
strcmp(dir_ent->d_name, "..") == 0)
792+
continue;
707793

708-
if (verbose && !check)
709-
elog(LOG, "creating directory \"%s\"",
710-
file->path + strlen(from_root) + 1);
711-
if (!check)
712-
dir_create_dir(to_path, DIR_PERMISSION);
713-
}
714-
else if (S_ISREG(file->mode))
715-
{
716-
if (verbose && !check)
717-
elog(LOG, "copying \"%s\"",
718-
file->path + strlen(from_root) + 1);
719-
if (!check)
720-
copy_file(from_root, to_root, file);
721-
}
794+
/* Directory is not empty */
795+
closedir(dir);
796+
return false;
722797
}
798+
if (errno)
799+
elog(ERROR, "cannot read directory \"%s\": %s", path, strerror(errno));
800+
801+
closedir(dir);
723802

724-
/* cleanup */
725-
parray_walk(files, pgFileFree);
726-
parray_free(files);
803+
return true;
727804
}

contrib/pg_probackup/doc/pg_probackup.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,12 @@ Specifies whether to stop just after the specified recovery target (true), or ju
477477

478478
Specifies recovering into a particular timeline.
479479

480+
-T
481+
--tablespace-mapping=OLDDIR=NEWDIR
482+
483+
Relocate the tablespace in directory `OLDDIR` to `NEWDIR` during restore. Both
484+
`OLDDIR` and `NEWDIR` must be absolute paths.
485+
480486
### Delete options:
481487

482488
--wal

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy