Skip to content

Commit 6e70ef9

Browse files
committed
Merge branch 'master' into release_2_6
2 parents 4ee8592 + 7e16642 commit 6e70ef9

File tree

6 files changed

+122
-74
lines changed

6 files changed

+122
-74
lines changed

src/catalog.c

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,15 +1091,15 @@ get_backup_filelist(pgBackup *backup, bool strict)
10911091

10921092
COMP_FILE_CRC32(true, content_crc, buf, strlen(buf));
10931093

1094-
get_control_value(buf, "path", path, NULL, true);
1095-
get_control_value(buf, "size", NULL, &write_size, true);
1096-
get_control_value(buf, "mode", NULL, &mode, true);
1097-
get_control_value(buf, "is_datafile", NULL, &is_datafile, true);
1098-
get_control_value(buf, "is_cfs", NULL, &is_cfs, false);
1099-
get_control_value(buf, "crc", NULL, &crc, true);
1100-
get_control_value(buf, "compress_alg", compress_alg_string, NULL, false);
1101-
get_control_value(buf, "external_dir_num", NULL, &external_dir_num, false);
1102-
get_control_value(buf, "dbOid", NULL, &dbOid, false);
1094+
get_control_value_str(buf, "path", path, sizeof(path),true);
1095+
get_control_value_int64(buf, "size", &write_size, true);
1096+
get_control_value_int64(buf, "mode", &mode, true);
1097+
get_control_value_int64(buf, "is_datafile", &is_datafile, true);
1098+
get_control_value_int64(buf, "is_cfs", &is_cfs, false);
1099+
get_control_value_int64(buf, "crc", &crc, true);
1100+
get_control_value_str(buf, "compress_alg", compress_alg_string, sizeof(compress_alg_string), false);
1101+
get_control_value_int64(buf, "external_dir_num", &external_dir_num, false);
1102+
get_control_value_int64(buf, "dbOid", &dbOid, false);
11031103

11041104
file = pgFileInit(path);
11051105
file->write_size = (int64) write_size;
@@ -1114,28 +1114,28 @@ get_backup_filelist(pgBackup *backup, bool strict)
11141114
/*
11151115
* Optional fields
11161116
*/
1117-
if (get_control_value(buf, "linked", linked, NULL, false) && linked[0])
1117+
if (get_control_value_str(buf, "linked", linked, sizeof(linked), false) && linked[0])
11181118
{
11191119
file->linked = pgut_strdup(linked);
11201120
canonicalize_path(file->linked);
11211121
}
11221122

1123-
if (get_control_value(buf, "segno", NULL, &segno, false))
1123+
if (get_control_value_int64(buf, "segno", &segno, false))
11241124
file->segno = (int) segno;
11251125

1126-
if (get_control_value(buf, "n_blocks", NULL, &n_blocks, false))
1126+
if (get_control_value_int64(buf, "n_blocks", &n_blocks, false))
11271127
file->n_blocks = (int) n_blocks;
11281128

1129-
if (get_control_value(buf, "n_headers", NULL, &n_headers, false))
1129+
if (get_control_value_int64(buf, "n_headers", &n_headers, false))
11301130
file->n_headers = (int) n_headers;
11311131

1132-
if (get_control_value(buf, "hdr_crc", NULL, &hdr_crc, false))
1132+
if (get_control_value_int64(buf, "hdr_crc", &hdr_crc, false))
11331133
file->hdr_crc = (pg_crc32) hdr_crc;
11341134

1135-
if (get_control_value(buf, "hdr_off", NULL, &hdr_off, false))
1135+
if (get_control_value_int64(buf, "hdr_off", &hdr_off, false))
11361136
file->hdr_off = hdr_off;
11371137

1138-
if (get_control_value(buf, "hdr_size", NULL, &hdr_size, false))
1138+
if (get_control_value_int64(buf, "hdr_size", &hdr_size, false))
11391139
file->hdr_size = (int) hdr_size;
11401140

11411141
parray_append(files, file);

src/dir.c

Lines changed: 71 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
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);
131132
static void cleanup_tablespace(const char *path);
132133

134+
static void control_string_bad_format(const char* str);
135+
136+
133137
/* Tablespace mapping */
134138
static TablespaceList tablespace_dirs = {NULL, NULL};
135139
/* Extra directories mapping */
@@ -1405,7 +1409,7 @@ get_external_remap(char *current_dir)
14051409
return current_dir;
14061410
}
14071411

1408-
/* Parsing states for get_control_value() */
1412+
/* Parsing states for get_control_value_str() */
14091413
#define CONTROL_WAIT_NAME 1
14101414
#define CONTROL_INNAME 2
14111415
#define CONTROL_WAIT_COLON 3
@@ -1419,26 +1423,62 @@ get_external_remap(char *current_dir)
14191423
* The line has the following format:
14201424
* {"name1":"value1", "name2":"value2"}
14211425
*
1422-
* The value will be returned to "value_str" as string if it is not NULL. If it
1423-
* is NULL the value will be returned to "value_int64" as int64.
1426+
* The value will be returned in "value_int64" as int64.
1427+
*
1428+
* Returns true if the value was found in the line and parsed.
1429+
*/
1430+
bool
1431+
get_control_value_int64(const char *str, const char *name, int64 *value_int64, bool is_mandatory)
1432+
{
1433+
1434+
char buf_int64[32];
1435+
1436+
assert(value_int64);
1437+
1438+
/* Set default value */
1439+
*value_int64 = 0;
1440+
1441+
if (!get_control_value_str(str, name, buf_int64, sizeof(buf_int64), is_mandatory))
1442+
return false;
1443+
1444+
if (!parse_int64(buf_int64, value_int64, 0))
1445+
{
1446+
/* We assume that too big value is -1 */
1447+
if (errno == ERANGE)
1448+
*value_int64 = BYTES_INVALID;
1449+
else
1450+
control_string_bad_format(str);
1451+
return false;
1452+
}
1453+
1454+
return true;
1455+
}
1456+
1457+
/*
1458+
* Get value from json-like line "str" of backup_content.control file.
1459+
*
1460+
* The line has the following format:
1461+
* {"name1":"value1", "name2":"value2"}
1462+
*
1463+
* The value will be returned to "value_str" as string.
14241464
*
14251465
* Returns true if the value was found in the line.
14261466
*/
1467+
14271468
bool
1428-
get_control_value(const char *str, const char *name,
1429-
char *value_str, int64 *value_int64, bool is_mandatory)
1469+
get_control_value_str(const char *str, const char *name,
1470+
char *value_str, size_t value_str_size, bool is_mandatory)
14301471
{
14311472
int state = CONTROL_WAIT_NAME;
14321473
char *name_ptr = (char *) name;
14331474
char *buf = (char *) str;
1434-
char buf_int64[32], /* Buffer for "value_int64" */
1435-
*buf_int64_ptr = buf_int64;
1475+
char *const value_str_start = value_str;
14361476

1437-
/* Set default values */
1438-
if (value_str)
1439-
*value_str = '\0';
1440-
else if (value_int64)
1441-
*value_int64 = 0;
1477+
assert(value_str);
1478+
assert(value_str_size > 0);
1479+
1480+
/* Set default value */
1481+
*value_str = '\0';
14421482

14431483
while (*buf)
14441484
{
@@ -1448,7 +1488,7 @@ get_control_value(const char *str, const char *name,
14481488
if (*buf == '"')
14491489
state = CONTROL_INNAME;
14501490
else if (IsAlpha(*buf))
1451-
goto bad_format;
1491+
control_string_bad_format(str);
14521492
break;
14531493
case CONTROL_INNAME:
14541494
/* Found target field. Parse value. */
@@ -1467,57 +1507,32 @@ get_control_value(const char *str, const char *name,
14671507
if (*buf == ':')
14681508
state = CONTROL_WAIT_VALUE;
14691509
else if (!IsSpace(*buf))
1470-
goto bad_format;
1510+
control_string_bad_format(str);
14711511
break;
14721512
case CONTROL_WAIT_VALUE:
14731513
if (*buf == '"')
14741514
{
14751515
state = CONTROL_INVALUE;
1476-
buf_int64_ptr = buf_int64;
14771516
}
14781517
else if (IsAlpha(*buf))
1479-
goto bad_format;
1518+
control_string_bad_format(str);
14801519
break;
14811520
case CONTROL_INVALUE:
14821521
/* Value was parsed, exit */
14831522
if (*buf == '"')
14841523
{
1485-
if (value_str)
1486-
{
1487-
*value_str = '\0';
1488-
}
1489-
else if (value_int64)
1490-
{
1491-
/* Length of buf_uint64 should not be greater than 31 */
1492-
if (buf_int64_ptr - buf_int64 >= 32)
1493-
elog(ERROR, "field \"%s\" is out of range in the line %s of the file %s",
1494-
name, str, DATABASE_FILE_LIST);
1495-
1496-
*buf_int64_ptr = '\0';
1497-
if (!parse_int64(buf_int64, value_int64, 0))
1498-
{
1499-
/* We assume that too big value is -1 */
1500-
if (errno == ERANGE)
1501-
*value_int64 = BYTES_INVALID;
1502-
else
1503-
goto bad_format;
1504-
}
1505-
}
1506-
1524+
*value_str = '\0';
15071525
return true;
15081526
}
15091527
else
15101528
{
1511-
if (value_str)
1512-
{
1513-
*value_str = *buf;
1514-
value_str++;
1515-
}
1516-
else
1517-
{
1518-
*buf_int64_ptr = *buf;
1519-
buf_int64_ptr++;
1529+
/* verify if value_str not exceeds value_str_size limits */
1530+
if (value_str - value_str_start >= value_str_size - 1) {
1531+
elog(ERROR, "field \"%s\" is out of range in the line %s of the file %s",
1532+
name, str, DATABASE_FILE_LIST);
15201533
}
1534+
*value_str = *buf;
1535+
value_str++;
15211536
}
15221537
break;
15231538
case CONTROL_WAIT_NEXT_NAME:
@@ -1534,18 +1549,20 @@ get_control_value(const char *str, const char *name,
15341549

15351550
/* There is no close quotes */
15361551
if (state == CONTROL_INNAME || state == CONTROL_INVALUE)
1537-
goto bad_format;
1552+
control_string_bad_format(str);
15381553

15391554
/* Did not find target field */
15401555
if (is_mandatory)
15411556
elog(ERROR, "field \"%s\" is not found in the line %s of the file %s",
15421557
name, str, DATABASE_FILE_LIST);
15431558
return false;
1559+
}
15441560

1545-
bad_format:
1546-
elog(ERROR, "%s file has invalid format in line %s",
1547-
DATABASE_FILE_LIST, str);
1548-
return false; /* Make compiler happy */
1561+
static void
1562+
control_string_bad_format(const char* str)
1563+
{
1564+
elog(ERROR, "%s file has invalid format in line %s",
1565+
DATABASE_FILE_LIST, str);
15491566
}
15501567

15511568
/*
@@ -1770,8 +1787,8 @@ read_database_map(pgBackup *backup)
17701787

17711788
db_map_entry *db_entry = (db_map_entry *) pgut_malloc(sizeof(db_map_entry));
17721789

1773-
get_control_value(buf, "dbOid", NULL, &dbOid, true);
1774-
get_control_value(buf, "datname", datname, NULL, true);
1790+
get_control_value_int64(buf, "dbOid", &dbOid, true);
1791+
get_control_value_str(buf, "datname", datname, sizeof(datname), true);
17751792

17761793
db_entry->dbOid = dbOid;
17771794
db_entry->datname = pgut_strdup(datname);

src/pg_probackup.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,8 +1010,9 @@ extern CompressAlg parse_compress_alg(const char *arg);
10101010
extern const char* deparse_compress_alg(int alg);
10111011

10121012
/* in dir.c */
1013-
extern bool get_control_value(const char *str, const char *name,
1014-
char *value_str, int64 *value_int64, bool is_mandatory);
1013+
extern bool get_control_value_int64(const char *str, const char *name, int64 *value_int64, bool is_mandatory);
1014+
extern bool get_control_value_str(const char *str, const char *name,
1015+
char *value_str, size_t value_str_size, bool is_mandatory);
10151016
extern void dir_list_file(parray *files, const char *root, bool exclude,
10161017
bool follow_symlink, bool add_root, bool backup_logs,
10171018
bool skip_hidden, int external_dir_num, fio_location location);

tests/Readme.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[see wiki](https://confluence.postgrespro.ru/display/DEV/pg_probackup)
1+
****[see wiki](https://confluence.postgrespro.ru/display/DEV/pg_probackup)
22

33
```
44
Note: For now these tests work on Linux and "kinda" work on Windows
@@ -50,3 +50,32 @@ Usage:
5050
export PG_CONFIG=/path/to/pg_config
5151
python -m unittest [-v] tests[.specific_module][.class.test]
5252
```
53+
54+
### Troubleshooting FAQ
55+
56+
#### python test failures
57+
1. Test failure reason like
58+
```
59+
testgres.exceptions.QueryException ERROR: could not open extension control file "/home/avaness/postgres/postgres.build/share/extension/amcheck.control": No such file or directory
60+
```
61+
62+
*Solution*: you have no `<postgres_src_root>/contrib/` extensions installed
63+
64+
```commandline
65+
cd <postgres_src_root>
66+
make world install
67+
```
68+
69+
2. Test failure
70+
71+
```
72+
FAIL: test_help_6 (tests.option.OptionTest)
73+
```
74+
75+
*Solution*: you didn't configure postgres build with `--enable-nls`
76+
77+
```commandline
78+
cd <postgres_src_root>
79+
make distclean
80+
<your-./configure-cmdline> --enable-nls
81+
```

tests/expected/option_help_ru.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ pg_probackup - утилита для управления резервным к
178178
[--remote-proto] [--remote-host]
179179
[--remote-port] [--remote-path] [--remote-user]
180180
[--ssh-options]
181+
[--dry-run]
181182
[--help]
182183

183184
Подробнее читайте на сайте <https://github.com/postgrespro/pg_probackup>.

tests/option.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def test_version_2(self):
2424
"""help options"""
2525
with open(os.path.join(self.dir_path, "expected/option_version.out"), "rb") as version_out:
2626
self.assertIn(
27-
version_out.read().decode("utf-8"),
27+
version_out.read().decode("utf-8").strip(),
2828
self.run_pb(["--version"])
2929
)
3030

0 commit comments

Comments
 (0)