@ -10702,19 +10702,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno)
* active at the same time , and they don ' t conflict with an exclusive backup
* active at the same time , and they don ' t conflict with an exclusive backup
* either .
* either .
*
*
* tablespaces is required only when this function is called while
* labelfile and tblspcmapfile must be passed as NULL when starting an
* the streaming base backup requested by pg_basebackup is running .
* exclusive backup , and as initially - empty StringInfos for a non - exclusive
* NULL should be specified otherwise .
* backup .
*
* If " tablespaces " isn ' t NULL , it receives a list of tablespaceinfo structs
* describing the cluster ' s tablespaces .
*
*
* tblspcmapfile is required mainly for tar format in windows as native windows
* tblspcmapfile is required mainly for tar format in windows as native windows
* utilities are not able to create symlinks while extracting files from tar .
* utilities are not able to create symlinks while extracting files from tar .
* However for consistency , the same is used for all platforms .
* However for consistency , the same is used for all platforms .
*
*
* needtblspcmapfile is true for the cases ( exclusive backup and for
* non - exclusive backup only when tar format is used for taking backup )
* when backup needs to generate tablespace_map file , it is used to
* embed escape character before newline character in tablespace path .
*
* Returns the minimum WAL location that must be present to restore from this
* Returns the minimum WAL location that must be present to restore from this
* backup , and the corresponding timeline ID in * starttli_p .
* backup , and the corresponding timeline ID in * starttli_p .
*
*
@ -10727,7 +10725,7 @@ issue_xlog_fsync(int fd, XLogSegNo segno)
XLogRecPtr
XLogRecPtr
do_pg_start_backup ( const char * backupidstr , bool fast , TimeLineID * starttli_p ,
do_pg_start_backup ( const char * backupidstr , bool fast , TimeLineID * starttli_p ,
StringInfo labelfile , List * * tablespaces ,
StringInfo labelfile , List * * tablespaces ,
StringInfo tblspcmapfile , bool needtblspcmapfile )
StringInfo tblspcmapfile )
{
{
bool exclusive = ( labelfile = = NULL ) ;
bool exclusive = ( labelfile = = NULL ) ;
bool backup_started_in_recovery = false ;
bool backup_started_in_recovery = false ;
@ -10940,9 +10938,10 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
XLogFileName ( xlogfilename , starttli , _logSegNo , wal_segment_size ) ;
XLogFileName ( xlogfilename , starttli , _logSegNo , wal_segment_size ) ;
/*
/*
* Construct tablespace_map file
* Construct tablespace_map file . If caller isn ' t interested in this ,
* we make a local StringInfo .
*/
*/
if ( exclusive )
if ( tblspcmapfile = = NULL )
tblspcmapfile = makeStringInfo ( ) ;
tblspcmapfile = makeStringInfo ( ) ;
datadirpathlen = strlen ( DataDir ) ;
datadirpathlen = strlen ( DataDir ) ;
@ -10955,11 +10954,11 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char linkpath [ MAXPGPATH ] ;
char linkpath [ MAXPGPATH ] ;
char * relpath = NULL ;
char * relpath = NULL ;
int rllen ;
int rllen ;
StringInfoData buflink path;
StringInfoData escaped path;
char * s = linkpath ;
char * s ;
/* Skip special stuff */
/* Skip anything that doesn't look like a tablespace */
if ( strcmp ( de - > d_name , " . " ) = = 0 | | strcmp ( de - > d_name , " .. " ) = = 0 )
if ( strspn ( de - > d_name , " 0123456789 " ) ! = strlen ( de - > d_name ) )
continue ;
continue ;
snprintf ( fullpath , sizeof ( fullpath ) , " pg_tblspc/%s " , de - > d_name ) ;
snprintf ( fullpath , sizeof ( fullpath ) , " pg_tblspc/%s " , de - > d_name ) ;
@ -10983,18 +10982,15 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
linkpath [ rllen ] = ' \0 ' ;
linkpath [ rllen ] = ' \0 ' ;
/*
/*
* Add the escape character ' \\ ' before newline in a string to
* Build a backslash - escaped version of the link path to include
* ensure that we can distinguish between the newline in the
* in the tablespace map file .
* tablespace path and end of line while reading tablespace_map
* file during archive recovery .
*/
*/
initStringInfo ( & buflinkpath ) ;
initStringInfo ( & escapedpath ) ;
for ( s = linkpath ; * s ; s + + )
while ( * s )
{
{
if ( ( * s = = ' \n ' | | * s = = ' \r ' ) & & needtblspcmapfile )
if ( * s = = ' \n ' | | * s = = ' \r ' | | * s = = ' \\ ' )
appendStringInfoChar ( & buflink path, ' \\ ' ) ;
appendStringInfoChar ( & escaped path, ' \\ ' ) ;
appendStringInfoChar ( & buflink path, * s + + ) ;
appendStringInfoChar ( & escaped path, * s ) ;
}
}
/*
/*
@ -11009,16 +11005,17 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
ti = palloc ( sizeof ( tablespaceinfo ) ) ;
ti = palloc ( sizeof ( tablespaceinfo ) ) ;
ti - > oid = pstrdup ( de - > d_name ) ;
ti - > oid = pstrdup ( de - > d_name ) ;
ti - > path = pstrdup ( buf linkpath. data ) ;
ti - > path = pstrdup ( linkpath ) ;
ti - > rpath = relpath ? pstrdup ( relpath ) : NULL ;
ti - > rpath = relpath ? pstrdup ( relpath ) : NULL ;
ti - > size = - 1 ;
ti - > size = - 1 ;
if ( tablespaces )
if ( tablespaces )
* tablespaces = lappend ( * tablespaces , ti ) ;
* tablespaces = lappend ( * tablespaces , ti ) ;
appendStringInfo ( tblspcmapfile , " %s %s \n " , ti - > oid , ti - > path ) ;
appendStringInfo ( tblspcmapfile , " %s %s \n " ,
ti - > oid , escapedpath . data ) ;
pfree ( buflink path. data ) ;
pfree ( escaped path. data ) ;
# else
# else
/*
/*
@ -11034,9 +11031,10 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
FreeDir ( tblspcdir ) ;
FreeDir ( tblspcdir ) ;
/*
/*
* Construct backup label file
* Construct backup label file . If caller isn ' t interested in this ,
* we make a local StringInfo .
*/
*/
if ( exclusive )
if ( labelfile = = NULL )
labelfile = makeStringInfo ( ) ;
labelfile = makeStringInfo ( ) ;
/* Use the log timezone here, not the session timezone */
/* Use the log timezone here, not the session timezone */
@ -11898,22 +11896,20 @@ read_backup_label(XLogRecPtr *checkPointLoc, bool *backupEndRequired,
* recovering from a backup dump file , and we therefore need to create symlinks
* recovering from a backup dump file , and we therefore need to create symlinks
* as per the information present in tablespace_map file .
* as per the information present in tablespace_map file .
*
*
* Returns true if a tablespace_map file was found ( and fills the link
* Returns true if a tablespace_map file was found ( and fills * tablespaces
* information for all the tablespace links present in file ) ; returns false
* with a tablespaceinfo struct for each tablespace listed in the file ) ;
* if not .
* returns false if not .
*/
*/
static bool
static bool
read_tablespace_map ( List * * tablespaces )
read_tablespace_map ( List * * tablespaces )
{
{
tablespaceinfo * ti ;
tablespaceinfo * ti ;
FILE * lfp ;
FILE * lfp ;
char tbsoid [ MAXPGPATH ] ;
char * tbslinkpath ;
char str [ MAXPGPATH ] ;
char str [ MAXPGPATH ] ;
int ch ,
int ch ,
prev_ch = - 1 ,
i ,
i = 0 ,
n ;
n ;
bool was_backslash ;
/*
/*
* See if tablespace_map file is present
* See if tablespace_map file is present
@ -11932,38 +11928,55 @@ read_tablespace_map(List **tablespaces)
/*
/*
* Read and parse the link name and path lines from tablespace_map file
* Read and parse the link name and path lines from tablespace_map file
* ( this code is pretty crude , but we are not expecting any variability in
* ( this code is pretty crude , but we are not expecting any variability in
* the file format ) . While taking backup we embed escape character ' \\ '
* the file format ) . De - escape any backslashes that were inserted .
* before newline in tablespace path , so that during reading of
* tablespace_map file , we could distinguish newline in tablespace path
* and end of line . Now while reading tablespace_map file , remove the
* escape character that has been added in tablespace path during backup .
*/
*/
i = 0 ;
was_backslash = false ;
while ( ( ch = fgetc ( lfp ) ) ! = EOF )
while ( ( ch = fgetc ( lfp ) ) ! = EOF )
{
{
if ( ( ch = = ' \n ' | | ch = = ' \r ' ) & & prev_ch ! = ' \\ ' )
if ( ! was_backslash & & ( ch = = ' \n ' | | ch = = ' \r ' ) )
{
{
if ( i = = 0 )
continue ; /* \r immediately followed by \n */
/*
* The de - escaped line should contain an OID followed by exactly
* one space followed by a path . The path might start with
* spaces , so don ' t be too liberal about parsing .
*/
str [ i ] = ' \0 ' ;
str [ i ] = ' \0 ' ;
if ( sscanf ( str , " %s %n " , tbsoid , & n ) ! = 1 )
n = 0 ;
while ( str [ n ] & & str [ n ] ! = ' ' )
n + + ;
if ( n < 1 | | n > = i - 1 )
ereport ( FATAL ,
ereport ( FATAL ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " invalid data in file \" %s \" " , TABLESPACE_MAP ) ) ) ;
errmsg ( " invalid data in file \" %s \" " , TABLESPACE_MAP ) ) ) ;
tbslinkpath = str + n ;
str [ n + + ] = ' \0 ' ;
i = 0 ;
ti = palloc ( sizeof ( tablespaceinfo ) ) ;
ti - > oid = pstrdup ( tbsoid ) ;
ti - > path = pstrdup ( tbslinkpath ) ;
ti = palloc0 ( sizeof ( tablespaceinfo ) ) ;
ti - > oid = pstrdup ( str ) ;
ti - > path = pstrdup ( str + n ) ;
* tablespaces = lappend ( * tablespaces , ti ) ;
* tablespaces = lappend ( * tablespaces , ti ) ;
i = 0 ;
continue ;
continue ;
}
}
else if ( ( ch = = ' \n ' | | ch = = ' \r ' ) & & prev_ch = = ' \\ ' )
else if ( ! was_backslash & & ch = = ' \\ ' )
str [ i - 1 ] = ch ;
was_backslash = true ;
else if ( i < sizeof ( str ) - 1 )
else
str [ i + + ] = ch ;
{
prev_ch = ch ;
if ( i < sizeof ( str ) - 1 )
str [ i + + ] = ch ;
was_backslash = false ;
}
}
}
if ( i ! = 0 | | was_backslash ) /* last line not terminated? */
ereport ( FATAL ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " invalid data in file \" %s \" " , TABLESPACE_MAP ) ) ) ;
if ( ferror ( lfp ) | | FreeFile ( lfp ) )
if ( ferror ( lfp ) | | FreeFile ( lfp ) )
ereport ( FATAL ,
ereport ( FATAL ,
( errcode_for_file_access ( ) ,
( errcode_for_file_access ( ) ,