88 *-------------------------------------------------------------------------
99 */
1010
11+ #include <assert.h>
1112#include "pg_probackup.h"
1213#include "utils/file.h"
1314
@@ -130,6 +131,9 @@ static void opt_path_map(ConfigOption *opt, const char *arg,
130131 TablespaceList * list , const char * type );
131132static void cleanup_tablespace (const char * path );
132133
134+ static void control_string_bad_format (const char * str );
135+
136+
133137/* Tablespace mapping */
134138static TablespaceList tablespace_dirs = {NULL , NULL };
135139/* Extra directories mapping */
@@ -1467,7 +1471,7 @@ get_external_remap(char *current_dir)
14671471 return current_dir ;
14681472}
14691473
1470- /* Parsing states for get_control_value () */
1474+ /* Parsing states for get_control_value_str () */
14711475#define CONTROL_WAIT_NAME 1
14721476#define CONTROL_INNAME 2
14731477#define CONTROL_WAIT_COLON 3
@@ -1481,26 +1485,62 @@ get_external_remap(char *current_dir)
14811485 * The line has the following format:
14821486 * {"name1":"value1", "name2":"value2"}
14831487 *
1484- * The value will be returned to "value_str" as string if it is not NULL. If it
1485- * is NULL the value will be returned to "value_int64" as int64.
1488+ * The value will be returned in "value_int64" as int64.
1489+ *
1490+ * Returns true if the value was found in the line and parsed.
1491+ */
1492+ bool
1493+ get_control_value_int64 (const char * str , const char * name , int64 * value_int64 , bool is_mandatory )
1494+ {
1495+
1496+ char buf_int64 [32 ];
1497+
1498+ assert (value_int64 );
1499+
1500+ /* Set default value */
1501+ * value_int64 = 0 ;
1502+
1503+ if (!get_control_value_str (str , name , buf_int64 , sizeof (buf_int64 ), is_mandatory ))
1504+ return false;
1505+
1506+ if (!parse_int64 (buf_int64 , value_int64 , 0 ))
1507+ {
1508+ /* We assume that too big value is -1 */
1509+ if (errno == ERANGE )
1510+ * value_int64 = BYTES_INVALID ;
1511+ else
1512+ control_string_bad_format (str );
1513+ return false;
1514+ }
1515+
1516+ return true;
1517+ }
1518+
1519+ /*
1520+ * Get value from json-like line "str" of backup_content.control file.
1521+ *
1522+ * The line has the following format:
1523+ * {"name1":"value1", "name2":"value2"}
1524+ *
1525+ * The value will be returned to "value_str" as string.
14861526 *
14871527 * Returns true if the value was found in the line.
14881528 */
1529+
14891530bool
1490- get_control_value (const char * str , const char * name ,
1491- char * value_str , int64 * value_int64 , bool is_mandatory )
1531+ get_control_value_str (const char * str , const char * name ,
1532+ char * value_str , size_t value_str_size , bool is_mandatory )
14921533{
14931534 int state = CONTROL_WAIT_NAME ;
14941535 char * name_ptr = (char * ) name ;
14951536 char * buf = (char * ) str ;
1496- char buf_int64 [32 ], /* Buffer for "value_int64" */
1497- * buf_int64_ptr = buf_int64 ;
1537+ char * const value_str_start = value_str ;
14981538
1499- /* Set default values */
1500- if ( value_str )
1501- * value_str = '\0' ;
1502- else if ( value_int64 )
1503- * value_int64 = 0 ;
1539+ assert ( value_str );
1540+ assert ( value_str_size > 0 );
1541+
1542+ /* Set default value */
1543+ * value_str = '\0' ;
15041544
15051545 while (* buf )
15061546 {
@@ -1510,7 +1550,7 @@ get_control_value(const char *str, const char *name,
15101550 if (* buf == '"' )
15111551 state = CONTROL_INNAME ;
15121552 else if (IsAlpha (* buf ))
1513- goto bad_format ;
1553+ control_string_bad_format ( str ) ;
15141554 break ;
15151555 case CONTROL_INNAME :
15161556 /* Found target field. Parse value. */
@@ -1529,57 +1569,32 @@ get_control_value(const char *str, const char *name,
15291569 if (* buf == ':' )
15301570 state = CONTROL_WAIT_VALUE ;
15311571 else if (!IsSpace (* buf ))
1532- goto bad_format ;
1572+ control_string_bad_format ( str ) ;
15331573 break ;
15341574 case CONTROL_WAIT_VALUE :
15351575 if (* buf == '"' )
15361576 {
15371577 state = CONTROL_INVALUE ;
1538- buf_int64_ptr = buf_int64 ;
15391578 }
15401579 else if (IsAlpha (* buf ))
1541- goto bad_format ;
1580+ control_string_bad_format ( str ) ;
15421581 break ;
15431582 case CONTROL_INVALUE :
15441583 /* Value was parsed, exit */
15451584 if (* buf == '"' )
15461585 {
1547- if (value_str )
1548- {
1549- * value_str = '\0' ;
1550- }
1551- else if (value_int64 )
1552- {
1553- /* Length of buf_uint64 should not be greater than 31 */
1554- if (buf_int64_ptr - buf_int64 >= 32 )
1555- elog (ERROR , "field \"%s\" is out of range in the line %s of the file %s" ,
1556- name , str , DATABASE_FILE_LIST );
1557-
1558- * buf_int64_ptr = '\0' ;
1559- if (!parse_int64 (buf_int64 , value_int64 , 0 ))
1560- {
1561- /* We assume that too big value is -1 */
1562- if (errno == ERANGE )
1563- * value_int64 = BYTES_INVALID ;
1564- else
1565- goto bad_format ;
1566- }
1567- }
1568-
1586+ * value_str = '\0' ;
15691587 return true;
15701588 }
15711589 else
15721590 {
1573- if (value_str )
1574- {
1575- * value_str = * buf ;
1576- value_str ++ ;
1577- }
1578- else
1579- {
1580- * buf_int64_ptr = * buf ;
1581- buf_int64_ptr ++ ;
1591+ /* verify if value_str not exceeds value_str_size limits */
1592+ if (value_str - value_str_start >= value_str_size - 1 ) {
1593+ elog (ERROR , "field \"%s\" is out of range in the line %s of the file %s" ,
1594+ name , str , DATABASE_FILE_LIST );
15821595 }
1596+ * value_str = * buf ;
1597+ value_str ++ ;
15831598 }
15841599 break ;
15851600 case CONTROL_WAIT_NEXT_NAME :
@@ -1596,18 +1611,20 @@ get_control_value(const char *str, const char *name,
15961611
15971612 /* There is no close quotes */
15981613 if (state == CONTROL_INNAME || state == CONTROL_INVALUE )
1599- goto bad_format ;
1614+ control_string_bad_format ( str ) ;
16001615
16011616 /* Did not find target field */
16021617 if (is_mandatory )
16031618 elog (ERROR , "field \"%s\" is not found in the line %s of the file %s" ,
16041619 name , str , DATABASE_FILE_LIST );
16051620 return false;
1621+ }
16061622
1607- bad_format :
1608- elog (ERROR , "%s file has invalid format in line %s" ,
1609- DATABASE_FILE_LIST , str );
1610- return false; /* Make compiler happy */
1623+ static void
1624+ control_string_bad_format (const char * str )
1625+ {
1626+ elog (ERROR , "%s file has invalid format in line %s" ,
1627+ DATABASE_FILE_LIST , str );
16111628}
16121629
16131630/*
@@ -1841,8 +1858,8 @@ read_database_map(pgBackup *backup)
18411858
18421859 db_map_entry * db_entry = (db_map_entry * ) pgut_malloc (sizeof (db_map_entry ));
18431860
1844- get_control_value (buf , "dbOid" , NULL , & dbOid , true);
1845- get_control_value (buf , "datname" , datname , NULL , true);
1861+ get_control_value_int64 (buf , "dbOid" , & dbOid , true);
1862+ get_control_value_str (buf , "datname" , datname , sizeof ( datname ) , true);
18461863
18471864 db_entry -> dbOid = dbOid ;
18481865 db_entry -> datname = pgut_strdup (datname );
0 commit comments