|
15 | 15 |
|
16 | 16 | #include "catalog/pg_control.h"
|
17 | 17 | #include "common/controldata_utils.h"
|
| 18 | +#include "common/relpath.h" |
18 | 19 | #include "getopt_long.h"
|
19 | 20 | #include "pg_getopt.h"
|
20 | 21 | #include "storage/bufpage.h"
|
@@ -49,27 +50,69 @@ usage(void)
|
49 | 50 | printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
|
50 | 51 | }
|
51 | 52 |
|
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 | + */ |
60 | 58 | static bool
|
61 |
| -skipfile(const char *fn) |
| 59 | +isRelFileName(const char *fn) |
62 | 60 | {
|
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') |
67 | 86 | return true;
|
68 | 87 |
|
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; |
73 | 116 | }
|
74 | 117 |
|
75 | 118 | static void
|
@@ -146,7 +189,7 @@ scan_directory(const char *basedir, const char *subdir)
|
146 | 189 | char fn[MAXPGPATH];
|
147 | 190 | struct stat st;
|
148 | 191 |
|
149 |
| - if (skipfile(de->d_name)) |
| 192 | + if (!isRelFileName(de->d_name)) |
150 | 193 | continue;
|
151 | 194 |
|
152 | 195 | snprintf(fn, sizeof(fn), "%s/%s", path, de->d_name);
|
|
0 commit comments