@@ -340,6 +340,16 @@ pgFileComparePath(const void *f1, const void *f2)
340
340
return strcmp (f1p -> path , f2p -> path );
341
341
}
342
342
343
+ /* Compare two pgFile with their name in ascending order of ASCII code. */
344
+ int
345
+ pgFileCompareName (const void * f1 , const void * f2 )
346
+ {
347
+ pgFile * f1p = * (pgFile * * )f1 ;
348
+ pgFile * f2p = * (pgFile * * )f2 ;
349
+
350
+ return strcmp (f1p -> name , f2p -> name );
351
+ }
352
+
343
353
/*
344
354
* Compare two pgFile with their path and external_dir_num
345
355
* in ascending order of ASCII code.
@@ -1041,6 +1051,142 @@ opt_externaldir_map(ConfigOption *opt, const char *arg)
1041
1051
opt_path_map (opt , arg , & external_remap_list , "external directory" );
1042
1052
}
1043
1053
1054
+ /*
1055
+ * Create backup directories from **backup_dir** to **data_dir**. Doesn't raise
1056
+ * an error if target directories exist.
1057
+ *
1058
+ * If **extract_tablespaces** is true then try to extract tablespace data
1059
+ * directories into their initial path using tablespace_map file.
1060
+ *
1061
+ * Enforce permissions from backup_content.control. The only
1062
+ * problem now is with PGDATA itself, we must preserve PGDATA permissions
1063
+ * somewhere.
1064
+ *
1065
+ * TODO: symlink handling. If user located symlink in PG_TBLSPC_DIR, it will
1066
+ * be restored as directory.
1067
+ */
1068
+ void
1069
+ create_data_directories (parray * dest_files , const char * data_dir , const char * backup_dir ,
1070
+ bool extract_tablespaces , fio_location location )
1071
+ {
1072
+ int i ;
1073
+ parray * links = NULL ;
1074
+ mode_t pg_tablespace_mode ;
1075
+ char to_path [MAXPGPATH ];
1076
+
1077
+ /* Ugly: get PG_TBLSPC_DIR pemission mask */
1078
+ for (i = 0 ; i < parray_num (dest_files ); i ++ )
1079
+ {
1080
+ pgFile * file = (pgFile * ) parray_get (dest_files , i );
1081
+
1082
+ if (!S_ISDIR (file -> mode ))
1083
+ continue ;
1084
+
1085
+ if (strcmp (file -> rel_path , PG_TBLSPC_DIR ) == 0 )
1086
+ {
1087
+ if (file -> external_dir_num == 0 )
1088
+ {
1089
+ pg_tablespace_mode = file -> mode ;
1090
+ break ;
1091
+ }
1092
+ }
1093
+ }
1094
+
1095
+ /* get tablespace map */
1096
+ if (extract_tablespaces )
1097
+ {
1098
+ links = parray_new ();
1099
+ read_tablespace_map (links , backup_dir );
1100
+ /* Sort links by a link name */
1101
+ parray_qsort (links , pgFileCompareName );
1102
+ }
1103
+
1104
+ /* Fun part is that backup_content.control is from beginning
1105
+ * of a backup, and tablespace_map is from the end
1106
+ * of a backup.
1107
+ * If we trust tablspace_map, we would have to we create first
1108
+ * tablespaces from it, then the start creating directories and files
1109
+ * from backup_content.
1110
+ * The problem if that backup_content could contain files from
1111
+ * deleted tablespaces and so would have to
1112
+ * check every file and directory if it comes from tablespace,
1113
+ * not presented in tablespace_map and skip it restoring if it
1114
+ * is not.
1115
+ * Trusting backup_content.control is safest way, there is no risk
1116
+ * of not restoring something.
1117
+ */
1118
+
1119
+ elog (LOG , "Restore directories and symlinks..." );
1120
+
1121
+ /* create directories */
1122
+ for (i = 0 ; i < parray_num (dest_files ); i ++ )
1123
+ {
1124
+ char parent_dir [MAXPGPATH ];
1125
+ pgFile * dir = (pgFile * ) parray_get (dest_files , i );
1126
+
1127
+ if (!S_ISDIR (dir -> mode ))
1128
+ continue ;
1129
+
1130
+ /* skip external directory content */
1131
+ if (dir -> external_dir_num != 0 )
1132
+ continue ;
1133
+
1134
+ /* tablespace_map exists */
1135
+ if (links )
1136
+ {
1137
+ /* get parent dir of rel_path */
1138
+ strncpy (parent_dir , dir -> rel_path , MAXPGPATH );
1139
+ get_parent_directory (parent_dir );
1140
+
1141
+ /* check if directory is actually link to tablespace */
1142
+ if (strcmp (parent_dir , PG_TBLSPC_DIR ) == 0 )
1143
+ {
1144
+ /* this directory located in pg_tblspc
1145
+ * check it against tablespace map
1146
+ */
1147
+ pgFile * * link = (pgFile * * ) parray_bsearch (links , dir , pgFileCompareName );
1148
+
1149
+ /* got match */
1150
+ if (link )
1151
+ {
1152
+ const char * linked_path = get_tablespace_mapping ((* link )-> linked );
1153
+
1154
+ if (!is_absolute_path (linked_path ))
1155
+ elog (ERROR , "Tablespace directory is not an absolute path: %s\n" ,
1156
+ linked_path );
1157
+
1158
+ join_path_components (to_path , data_dir , dir -> rel_path );
1159
+
1160
+ elog (VERBOSE , "Create directory \"%s\" and symbolic link \"%s\"" ,
1161
+ linked_path , to_path );
1162
+
1163
+ /* create tablespace directory */
1164
+ fio_mkdir (linked_path , pg_tablespace_mode , location );
1165
+
1166
+ /* create link to linked_path */
1167
+ if (fio_symlink (linked_path , to_path , location ) < 0 )
1168
+ elog (ERROR , "Could not create symbolic link \"%s\": %s" ,
1169
+ to_path , strerror (errno ));
1170
+
1171
+ continue ;
1172
+ }
1173
+ }
1174
+ }
1175
+
1176
+ /* This is not symlink, create directory */
1177
+ elog (INFO , "Create directory \"%s\"" , dir -> rel_path );
1178
+
1179
+ join_path_components (to_path , data_dir , dir -> rel_path );
1180
+ fio_mkdir (to_path , dir -> mode , location );
1181
+ }
1182
+
1183
+ if (extract_tablespaces )
1184
+ {
1185
+ parray_walk (links , pgFileFree );
1186
+ parray_free (links );
1187
+ }
1188
+ }
1189
+
1044
1190
/*
1045
1191
* Create backup directories from **backup_dir** to **data_dir**. Doesn't raise
1046
1192
* an error if target directories exist.
@@ -1049,7 +1195,7 @@ opt_externaldir_map(ConfigOption *opt, const char *arg)
1049
1195
* directories into their initial path using tablespace_map file.
1050
1196
*/
1051
1197
void
1052
- create_data_directories (const char * data_dir , const char * backup_dir ,
1198
+ create_data_directories_manual (const char * data_dir , const char * backup_dir ,
1053
1199
bool extract_tablespaces , fio_location location )
1054
1200
{
1055
1201
parray * dirs ,
@@ -1234,6 +1380,8 @@ read_tablespace_map(parray *files, const char *backup_dir)
1234
1380
file -> path = pgut_malloc (strlen (link_name ) + 1 );
1235
1381
strcpy (file -> path , link_name );
1236
1382
1383
+ file -> name = file -> path ;
1384
+
1237
1385
file -> linked = pgut_malloc (strlen (path ) + 1 );
1238
1386
strcpy (file -> linked , path );
1239
1387
0 commit comments