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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy