Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit cc7f27e

Browse files
committed
Use whitelist to choose files scanned with pg_verify_checksums
The original implementation of pg_verify_checksums used a blacklist to decide which files should be skipped for scanning as they do not include data checksums, like pg_internal.init or pg_control. However, this missed two things: - Some files are created within builds of EXEC_BACKEND and these were not listed, causing failures on Windows. - Extensions may create custom files in data folders, causing the tool to equally fail. This commit switches to a whitelist-like method instead by checking if the files to scan are authorized relation files. This is close to a reverse-engineering of what is defined in relpath.c in charge of building the relation paths, and we could consider refactoring what this patch does so as all routines are in a single place. This is left for later. This is based on a suggestion from Andres Freund. TAP tests are updated so as multiple file patterns are tested. The bug has been spotted by various buildfarm members as a result of b34e84f which has introduced the TAP tests of pg_verify_checksums. Author: Michael Paquier Reviewed-by: Andrew Dunstan, Michael Banck Discussion: https://postgr.es/m/20181012005614.GC26424@paquier.xyz Backpatch-through: 11
1 parent 06292bb commit cc7f27e

File tree

1 file changed

+61
-18
lines changed

1 file changed

+61
-18
lines changed

src/bin/pg_verify_checksums/pg_verify_checksums.c

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "catalog/pg_control.h"
1717
#include "common/controldata_utils.h"
18+
#include "common/relpath.h"
1819
#include "getopt_long.h"
1920
#include "pg_getopt.h"
2021
#include "storage/bufpage.h"
@@ -49,27 +50,69 @@ usage(void)
4950
printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
5051
}
5152

52-
static const char *const skip[] = {
53-
"pg_control",
54-
"pg_filenode.map",
55-
"pg_internal.init",
56-
"PG_VERSION",
57-
NULL,
58-
};
59-
53+
/*
54+
* isRelFileName
55+
*
56+
* Check if the given file name is authorized for checksum verification.
57+
*/
6058
static bool
61-
skipfile(const char *fn)
59+
isRelFileName(const char *fn)
6260
{
63-
const char *const *f;
64-
65-
if (strcmp(fn, ".") == 0 ||
66-
strcmp(fn, "..") == 0)
61+
int pos;
62+
63+
/*----------
64+
* Only files including data checksums are authorized for verification.
65+
* This is guessed based on the file name by reverse-engineering
66+
* GetRelationPath() so make sure to update both code paths if any
67+
* updates are done. The following file name formats are allowed:
68+
* <digits>
69+
* <digits>.<segment>
70+
* <digits>_<forkname>
71+
* <digits>_<forkname>.<segment>
72+
*
73+
* Note that temporary files, beginning with 't', are also skipped.
74+
*
75+
*----------
76+
*/
77+
78+
/* A non-empty string of digits should follow */
79+
for (pos = 0; isdigit((unsigned char) fn[pos]); ++pos)
80+
;
81+
/* leave if no digits */
82+
if (pos == 0)
83+
return false;
84+
/* good to go if only digits */
85+
if (fn[pos] == '\0')
6786
return true;
6887

69-
for (f = skip; *f; f++)
70-
if (strcmp(*f, fn) == 0)
71-
return true;
72-
return false;
88+
/* Authorized fork files can be scanned */
89+
if (fn[pos] == '_')
90+
{
91+
int forkchar = forkname_chars(&fn[pos + 1], NULL);
92+
93+
if (forkchar <= 0)
94+
return false;
95+
96+
pos += forkchar + 1;
97+
}
98+
99+
/* Check for an optional segment number */
100+
if (fn[pos] == '.')
101+
{
102+
int segchar;
103+
104+
for (segchar = 1; isdigit((unsigned char) fn[pos + segchar]); ++segchar)
105+
;
106+
107+
if (segchar <= 1)
108+
return false;
109+
pos += segchar;
110+
}
111+
112+
/* Now this should be the end */
113+
if (fn[pos] != '\0')
114+
return false;
115+
return true;
73116
}
74117

75118
static void
@@ -146,7 +189,7 @@ scan_directory(const char *basedir, const char *subdir)
146189
char fn[MAXPGPATH];
147190
struct stat st;
148191

149-
if (skipfile(de->d_name))
192+
if (!isRelFileName(de->d_name))
150193
continue;
151194

152195
snprintf(fn, sizeof(fn), "%s/%s", path, de->d_name);

0 commit comments

Comments
 (0)