1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2025-01-05 13:20:31 +02:00

Issue 67: permission mask is not preserved by restore

This commit is contained in:
Grigory Smolkin 2019-05-27 11:27:43 +03:00
parent 84c6fd4101
commit ead629bfa7
4 changed files with 159 additions and 4 deletions

150
src/dir.c
View File

@ -340,6 +340,16 @@ pgFileComparePath(const void *f1, const void *f2)
return strcmp(f1p->path, f2p->path);
}
/* Compare two pgFile with their name in ascending order of ASCII code. */
int
pgFileCompareName(const void *f1, const void *f2)
{
pgFile *f1p = *(pgFile **)f1;
pgFile *f2p = *(pgFile **)f2;
return strcmp(f1p->name, f2p->name);
}
/*
* Compare two pgFile with their path and external_dir_num
* in ascending order of ASCII code.
@ -1047,9 +1057,145 @@ opt_externaldir_map(ConfigOption *opt, const char *arg)
*
* If **extract_tablespaces** is true then try to extract tablespace data
* directories into their initial path using tablespace_map file.
*
* Enforce permissions from backup_content.control. The only
* problem now is with PGDATA itself, we must preserve PGDATA permissions
* somewhere.
*
* TODO: symlink handling. If user located symlink in PG_TBLSPC_DIR, it will
* be restored as directory.
*/
void
create_data_directories(const char *data_dir, const char *backup_dir,
create_data_directories(parray *dest_files, const char *data_dir, const char *backup_dir,
bool extract_tablespaces, fio_location location)
{
int i;
parray *links = NULL;
mode_t pg_tablespace_mode;
char to_path[MAXPGPATH];
/* Ugly: get PG_TBLSPC_DIR pemission mask */
for (i = 0; i < parray_num(dest_files); i++)
{
pgFile *file = (pgFile *) parray_get(dest_files, i);
if (!S_ISDIR(file->mode))
continue;
if (strcmp(file->rel_path, PG_TBLSPC_DIR) == 0)
{
if (file->external_dir_num == 0)
{
pg_tablespace_mode = file->mode;
break;
}
}
}
/* get tablespace map */
if (extract_tablespaces)
{
links = parray_new();
read_tablespace_map(links, backup_dir);
/* Sort links by a link name */
parray_qsort(links, pgFileCompareName);
}
/* Fun part is that backup_content.control is from beginning
* of a backup, and tablespace_map is from the end
* of a backup.
* If we trust tablspace_map, we would have to we create first
* tablespaces from it, then the start creating directories and files
* from backup_content.
* The problem if that backup_content could contain files from
* deleted tablespaces and so would have to
* check every file and directory if it comes from tablespace,
* not presented in tablespace_map and skip it restoring if it
* is not.
* Trusting backup_content.control is safest way, there is no risk
* of not restoring something.
*/
elog(LOG, "Restore directories and symlinks...");
/* create directories */
for (i = 0; i < parray_num(dest_files); i++)
{
char parent_dir[MAXPGPATH];
pgFile *dir = (pgFile *) parray_get(dest_files, i);
if (!S_ISDIR(dir->mode))
continue;
/* skip external directory content */
if (dir->external_dir_num != 0)
continue;
/* tablespace_map exists */
if (links)
{
/* get parent dir of rel_path */
strncpy(parent_dir, dir->rel_path, MAXPGPATH);
get_parent_directory(parent_dir);
/* check if directory is actually link to tablespace */
if (strcmp(parent_dir, PG_TBLSPC_DIR) == 0)
{
/* this directory located in pg_tblspc
* check it against tablespace map
*/
pgFile **link = (pgFile **) parray_bsearch(links, dir, pgFileCompareName);
/* got match */
if (link)
{
const char *linked_path = get_tablespace_mapping((*link)->linked);
if (!is_absolute_path(linked_path))
elog(ERROR, "Tablespace directory is not an absolute path: %s\n",
linked_path);
join_path_components(to_path, data_dir, dir->rel_path);
elog(VERBOSE, "Create directory \"%s\" and symbolic link \"%s\"",
linked_path, to_path);
/* create tablespace directory */
fio_mkdir(linked_path, pg_tablespace_mode, location);
/* create link to linked_path */
if (fio_symlink(linked_path, to_path, location) < 0)
elog(ERROR, "Could not create symbolic link \"%s\": %s",
to_path, strerror(errno));
continue;
}
}
}
/* This is not symlink, create directory */
elog(INFO, "Create directory \"%s\"", dir->rel_path);
join_path_components(to_path, data_dir, dir->rel_path);
fio_mkdir(to_path, dir->mode, location);
}
if (extract_tablespaces)
{
parray_walk(links, pgFileFree);
parray_free(links);
}
}
/*
* Create backup directories from **backup_dir** to **data_dir**. Doesn't raise
* an error if target directories exist.
*
* If **extract_tablespaces** is true then try to extract tablespace data
* directories into their initial path using tablespace_map file.
*/
void
create_data_directories_manual(const char *data_dir, const char *backup_dir,
bool extract_tablespaces, fio_location location)
{
parray *dirs,
@ -1234,6 +1380,8 @@ read_tablespace_map(parray *files, const char *backup_dir)
file->path = pgut_malloc(strlen(link_name) + 1);
strcpy(file->path, link_name);
file->name = file->path;
file->linked = pgut_malloc(strlen(path) + 1);
strcpy(file->linked, path);

View File

@ -255,7 +255,7 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
write_backup_status(to_backup, BACKUP_STATUS_MERGING);
write_backup_status(from_backup, BACKUP_STATUS_MERGING);
create_data_directories(to_database_path, from_backup_path, false, FIO_BACKUP_HOST);
create_data_directories(files, to_database_path, from_backup_path, false, FIO_BACKUP_HOST);
threads = (pthread_t *) palloc(sizeof(pthread_t) * num_threads);
threads_args = (merge_files_arg *) palloc(sizeof(merge_files_arg) * num_threads);

View File

@ -577,11 +577,17 @@ extern const char* deparse_compress_alg(int alg);
extern void dir_list_file(parray *files, const char *root, bool exclude,
bool omit_symlink, bool add_root, int external_dir_num, fio_location location);
extern void create_data_directories(const char *data_dir,
extern void create_data_directories_manual(const char *data_dir,
const char *backup_dir,
bool extract_tablespaces,
fio_location location);
extern void create_data_directories(parray *dest_files,
const char *data_dir,
const char *backup_dir,
bool extract_tablespaces,
fio_location location);
extern void read_tablespace_map(parray *files, const char *backup_dir);
extern void opt_tablespace_map(ConfigOption *opt, const char *arg);
extern void opt_externaldir_map(ConfigOption *opt, const char *arg);
@ -614,6 +620,7 @@ extern void pgFileDelete(pgFile *file);
extern void pgFileFree(void *file);
extern pg_crc32 pgFileGetCRC(const char *file_path, bool use_crc32c,
bool raise_on_deleted, size_t *bytes_read, fio_location location);
extern int pgFileCompareName(const void *f1, const void *f2);
extern int pgFileComparePath(const void *f1, const void *f2);
extern int pgFileComparePathWithExternal(const void *f1, const void *f2);
extern int pgFileCompareRelPathWithExternal(const void *f1, const void *f2);

View File

@ -442,7 +442,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
*/
pgBackupGetPath(dest_backup, dest_backup_path,
lengthof(dest_backup_path), NULL);
create_data_directories(instance_config.pgdata, dest_backup_path, true,
create_data_directories(dest_files, instance_config.pgdata, dest_backup_path, true,
FIO_DB_HOST);
/*