PostgreSQL Source Code git master
pg_checksums.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_checksums.c
4 * Checks, enables or disables page level checksums for an offline
5 * cluster
6 *
7 * Copyright (c) 2010-2025, PostgreSQL Global Development Group
8 *
9 * IDENTIFICATION
10 * src/bin/pg_checksums/pg_checksums.c
11 *
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres_fe.h"
16
17#include <dirent.h>
18#include <limits.h>
19#include <sys/stat.h>
20#include <time.h>
21#include <unistd.h>
22
24#include "common/file_utils.h"
25#include "common/logging.h"
26#include "common/relpath.h"
28#include "fe_utils/version.h"
29#include "getopt_long.h"
30#include "pg_getopt.h"
31#include "storage/bufpage.h"
32#include "storage/checksum.h"
34
35
40static int64 badblocks = 0;
42
43static char *only_filenode = NULL;
44static bool do_sync = true;
45static bool verbose = false;
46static bool showprogress = false;
48
49typedef enum
50{
55
57
58static const char *progname;
59
60/*
61 * Progress status information.
62 */
63static int64 total_size = 0;
66
67static void
68usage(void)
69{
70 printf(_("%s enables, disables, or verifies data checksums in a PostgreSQL database cluster.\n\n"), progname);
71 printf(_("Usage:\n"));
72 printf(_(" %s [OPTION]... [DATADIR]\n"), progname);
73 printf(_("\nOptions:\n"));
74 printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
75 printf(_(" -c, --check check data checksums (default)\n"));
76 printf(_(" -d, --disable disable data checksums\n"));
77 printf(_(" -e, --enable enable data checksums\n"));
78 printf(_(" -f, --filenode=FILENODE check only relation with specified filenode\n"));
79 printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n"));
80 printf(_(" -P, --progress show progress information\n"));
81 printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
82 printf(_(" -v, --verbose output verbose messages\n"));
83 printf(_(" -V, --version output version information, then exit\n"));
84 printf(_(" -?, --help show this help, then exit\n"));
85 printf(_("\nIf no data directory (DATADIR) is specified, "
86 "the environment variable PGDATA\nis used.\n\n"));
87 printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
88 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
89}
90
91/*
92 * Definition of one element part of an exclusion list, used for files
93 * to exclude from checksum validation. "name" is the name of the file
94 * or path to check for exclusion. If "match_prefix" is true, any items
95 * matching the name as prefix are excluded.
96 */
98{
99 const char *name;
100 bool match_prefix;
101};
102
103/*
104 * List of files excluded from checksum validation.
105 *
106 * Note: this list should be kept in sync with what basebackup.c includes.
107 */
108static const struct exclude_list_item skip[] = {
109 {"pg_control", false},
110 {"pg_filenode.map", false},
111 {"pg_internal.init", true},
112 {"PG_VERSION", false},
113#ifdef EXEC_BACKEND
114 {"config_exec_params", true},
115#endif
116 {NULL, false}
117};
118
119/*
120 * Report current progress status. Parts borrowed from
121 * src/bin/pg_basebackup/pg_basebackup.c.
122 */
123static void
124progress_report(bool finished)
125{
126 int percent;
128
130
131 now = time(NULL);
132 if (now == last_progress_report && !finished)
133 return; /* Max once per second */
134
135 /* Save current time */
137
138 /* Adjust total size if current_size is larger */
141
142 /* Calculate current percentage of size done */
143 percent = total_size ? (int) ((current_size) * 100 / total_size) : 0;
144
145 fprintf(stderr, _("%" PRId64 "/%" PRId64 " MB (%d%%) computed"),
146 (current_size / (1024 * 1024)),
147 (total_size / (1024 * 1024)),
148 percent);
149
150 /*
151 * Stay on the same line if reporting to a terminal and we're not done
152 * yet.
153 */
154 fputc((!finished && isatty(fileno(stderr))) ? '\r' : '\n', stderr);
155}
156
157static bool
158skipfile(const char *fn)
159{
160 int excludeIdx;
161
162 for (excludeIdx = 0; skip[excludeIdx].name != NULL; excludeIdx++)
163 {
164 int cmplen = strlen(skip[excludeIdx].name);
165
166 if (!skip[excludeIdx].match_prefix)
167 cmplen++;
168 if (strncmp(skip[excludeIdx].name, fn, cmplen) == 0)
169 return true;
170 }
171
172 return false;
173}
174
175static void
176scan_file(const char *fn, int segmentno)
177{
179 PageHeader header = (PageHeader) buf.data;
180 int f;
181 BlockNumber blockno;
182 int flags;
183 int64 blocks_written_in_file = 0;
184
187
188 flags = (mode == PG_MODE_ENABLE) ? O_RDWR : O_RDONLY;
189 f = open(fn, PG_BINARY | flags, 0);
190
191 if (f < 0)
192 pg_fatal("could not open file \"%s\": %m", fn);
193
195
196 for (blockno = 0;; blockno++)
197 {
198 uint16 csum;
199 int r = read(f, buf.data, BLCKSZ);
200
201 if (r == 0)
202 break;
203 if (r != BLCKSZ)
204 {
205 if (r < 0)
206 pg_fatal("could not read block %u in file \"%s\": %m",
207 blockno, fn);
208 else
209 pg_fatal("could not read block %u in file \"%s\": read %d of %d",
210 blockno, fn, r, BLCKSZ);
211 }
213
214 /*
215 * Since the file size is counted as total_size for progress status
216 * information, the sizes of all pages including new ones in the file
217 * should be counted as current_size. Otherwise the progress reporting
218 * calculated using those counters may not reach 100%.
219 */
220 current_size += r;
221
222 /* New pages have no checksum yet */
223 if (PageIsNew(buf.data))
224 continue;
225
226 csum = pg_checksum_page(buf.data, blockno + segmentno * RELSEG_SIZE);
227 if (mode == PG_MODE_CHECK)
228 {
229 if (csum != header->pd_checksum)
230 {
232 pg_log_error("checksum verification failed in file \"%s\", block %u: calculated checksum %X but block contains %X",
233 fn, blockno, csum, header->pd_checksum);
234 badblocks++;
235 }
236 }
237 else if (mode == PG_MODE_ENABLE)
238 {
239 int w;
240
241 /*
242 * Do not rewrite if the checksum is already set to the expected
243 * value.
244 */
245 if (header->pd_checksum == csum)
246 continue;
247
248 blocks_written_in_file++;
249
250 /* Set checksum in page header */
251 header->pd_checksum = csum;
252
253 /* Seek back to beginning of block */
254 if (lseek(f, -BLCKSZ, SEEK_CUR) < 0)
255 pg_fatal("seek failed for block %u in file \"%s\": %m", blockno, fn);
256
257 /* Write block with checksum */
258 w = write(f, buf.data, BLCKSZ);
259 if (w != BLCKSZ)
260 {
261 if (w < 0)
262 pg_fatal("could not write block %u in file \"%s\": %m",
263 blockno, fn);
264 else
265 pg_fatal("could not write block %u in file \"%s\": wrote %d of %d",
266 blockno, fn, w, BLCKSZ);
267 }
268 }
269
270 if (showprogress)
271 progress_report(false);
272 }
273
274 if (verbose)
275 {
276 if (mode == PG_MODE_CHECK)
277 pg_log_info("checksums verified in file \"%s\"", fn);
278 if (mode == PG_MODE_ENABLE)
279 pg_log_info("checksums enabled in file \"%s\"", fn);
280 }
281
282 /* Update write counters if any write activity has happened */
283 if (blocks_written_in_file > 0)
284 {
286 blocks_written += blocks_written_in_file;
287 }
288
289 close(f);
290}
291
292/*
293 * Scan the given directory for items which can be checksummed and
294 * operate on each one of them. If "sizeonly" is true, the size of
295 * all the items which have checksums is computed and returned back
296 * to the caller without operating on the files. This is used to compile
297 * the total size of the data directory for progress reports.
298 */
299static int64
300scan_directory(const char *basedir, const char *subdir, bool sizeonly)
301{
302 int64 dirsize = 0;
303 char path[MAXPGPATH];
304 DIR *dir;
305 struct dirent *de;
306
307 snprintf(path, sizeof(path), "%s/%s", basedir, subdir);
308 dir = opendir(path);
309 if (!dir)
310 pg_fatal("could not open directory \"%s\": %m", path);
311 while ((de = readdir(dir)) != NULL)
312 {
313 char fn[MAXPGPATH];
314 struct stat st;
315
316 if (strcmp(de->d_name, ".") == 0 ||
317 strcmp(de->d_name, "..") == 0)
318 continue;
319
320 /* Skip temporary files */
321 if (strncmp(de->d_name,
323 strlen(PG_TEMP_FILE_PREFIX)) == 0)
324 continue;
325
326 /* Skip temporary folders */
327 if (strncmp(de->d_name,
329 strlen(PG_TEMP_FILES_DIR)) == 0)
330 continue;
331
332 /* Skip macOS system files */
333 if (strcmp(de->d_name, ".DS_Store") == 0)
334 continue;
335
336 snprintf(fn, sizeof(fn), "%s/%s", path, de->d_name);
337 if (lstat(fn, &st) < 0)
338 pg_fatal("could not stat file \"%s\": %m", fn);
339 if (S_ISREG(st.st_mode))
340 {
341 char fnonly[MAXPGPATH];
342 char *forkpath,
343 *segmentpath;
344 int segmentno = 0;
345
346 if (skipfile(de->d_name))
347 continue;
348
349 /*
350 * Cut off at the segment boundary (".") to get the segment number
351 * in order to mix it into the checksum. Then also cut off at the
352 * fork boundary, to get the filenode the file belongs to for
353 * filtering.
354 */
355 strlcpy(fnonly, de->d_name, sizeof(fnonly));
356 segmentpath = strchr(fnonly, '.');
357 if (segmentpath != NULL)
358 {
359 *segmentpath++ = '\0';
360 segmentno = atoi(segmentpath);
361 if (segmentno == 0)
362 pg_fatal("invalid segment number %d in file name \"%s\"",
363 segmentno, fn);
364 }
365
366 forkpath = strchr(fnonly, '_');
367 if (forkpath != NULL)
368 *forkpath++ = '\0';
369
370 if (only_filenode && strcmp(only_filenode, fnonly) != 0)
371 /* filenode not to be included */
372 continue;
373
374 dirsize += st.st_size;
375
376 /*
377 * No need to work on the file when calculating only the size of
378 * the items in the data folder.
379 */
380 if (!sizeonly)
381 scan_file(fn, segmentno);
382 }
383 else if (S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
384 {
385 /*
386 * If going through the entries of pg_tblspc, we assume to operate
387 * on tablespace locations where only TABLESPACE_VERSION_DIRECTORY
388 * is valid, resolving the linked locations and dive into them
389 * directly.
390 */
391 if (strncmp(PG_TBLSPC_DIR, subdir, strlen(PG_TBLSPC_DIR)) == 0)
392 {
393 char tblspc_path[MAXPGPATH];
394 struct stat tblspc_st;
395
396 /*
397 * Resolve tablespace location path and check whether
398 * TABLESPACE_VERSION_DIRECTORY exists. Not finding a valid
399 * location is unexpected, since there should be no orphaned
400 * links and no links pointing to something else than a
401 * directory.
402 */
403 snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s/%s",
405
406 if (lstat(tblspc_path, &tblspc_st) < 0)
407 pg_fatal("could not stat file \"%s\": %m",
408 tblspc_path);
409
410 /*
411 * Move backwards once as the scan needs to happen for the
412 * contents of TABLESPACE_VERSION_DIRECTORY.
413 */
414 snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s",
415 path, de->d_name);
416
417 /* Looks like a valid tablespace location */
418 dirsize += scan_directory(tblspc_path,
420 sizeonly);
421 }
422 else
423 {
424 dirsize += scan_directory(path, de->d_name, sizeonly);
425 }
426 }
427 }
428 closedir(dir);
429 return dirsize;
430}
431
432int
433main(int argc, char *argv[])
434{
435 static struct option long_options[] = {
436 {"check", no_argument, NULL, 'c'},
437 {"pgdata", required_argument, NULL, 'D'},
438 {"disable", no_argument, NULL, 'd'},
439 {"enable", no_argument, NULL, 'e'},
440 {"filenode", required_argument, NULL, 'f'},
441 {"no-sync", no_argument, NULL, 'N'},
442 {"progress", no_argument, NULL, 'P'},
443 {"verbose", no_argument, NULL, 'v'},
444 {"sync-method", required_argument, NULL, 1},
445 {NULL, 0, NULL, 0}
446 };
447
448 char *DataDir = NULL;
449 int c;
450 int option_index;
451 bool crc_ok;
452 uint32 major_version;
453 char *version_str;
454
455 pg_logging_init(argv[0]);
456 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_checksums"));
457 progname = get_progname(argv[0]);
458
459 if (argc > 1)
460 {
461 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
462 {
463 usage();
464 exit(0);
465 }
466 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
467 {
468 puts("pg_checksums (PostgreSQL) " PG_VERSION);
469 exit(0);
470 }
471 }
472
473 while ((c = getopt_long(argc, argv, "cdD:ef:NPv", long_options, &option_index)) != -1)
474 {
475 switch (c)
476 {
477 case 'c':
479 break;
480 case 'd':
482 break;
483 case 'D':
484 DataDir = optarg;
485 break;
486 case 'e':
488 break;
489 case 'f':
490 if (!option_parse_int(optarg, "-f/--filenode", 0,
491 INT_MAX,
492 NULL))
493 exit(1);
495 break;
496 case 'N':
497 do_sync = false;
498 break;
499 case 'P':
500 showprogress = true;
501 break;
502 case 'v':
503 verbose = true;
504 break;
505 case 1:
507 exit(1);
508 break;
509 default:
510 /* getopt_long already emitted a complaint */
511 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
512 exit(1);
513 }
514 }
515
516 if (DataDir == NULL)
517 {
518 if (optind < argc)
519 DataDir = argv[optind++];
520 else
521 DataDir = getenv("PGDATA");
522
523 /* If no DataDir was specified, and none could be found, error out */
524 if (DataDir == NULL)
525 {
526 pg_log_error("no data directory specified");
527 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
528 exit(1);
529 }
530 }
531
532 /* Complain if any arguments remain */
533 if (optind < argc)
534 {
535 pg_log_error("too many command-line arguments (first is \"%s\")",
536 argv[optind]);
537 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
538 exit(1);
539 }
540
541 /* filenode checking only works in --check mode */
543 {
544 pg_log_error("option -f/--filenode can only be used with --check");
545 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
546 exit(1);
547 }
548
549 /*
550 * Retrieve the contents of this cluster's PG_VERSION. We require
551 * compatibility with the same major version as the one this tool is
552 * compiled with.
553 */
554 major_version = GET_PG_MAJORVERSION_NUM(get_pg_version(DataDir, &version_str));
555 if (major_version != PG_MAJORVERSION_NUM)
556 {
557 pg_log_error("data directory is of wrong version");
558 pg_log_error_detail("File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".",
559 "PG_VERSION", version_str, PG_MAJORVERSION);
560 exit(1);
561 }
562
563 /* Read the control file and check compatibility */
565 if (!crc_ok)
566 pg_fatal("pg_control CRC value is incorrect");
567
569 pg_fatal("cluster is not compatible with this version of pg_checksums");
570
571 if (ControlFile->blcksz != BLCKSZ)
572 {
573 pg_log_error("database cluster is not compatible");
574 pg_log_error_detail("The database cluster was initialized with block size %u, but pg_checksums was compiled with block size %u.",
575 ControlFile->blcksz, BLCKSZ);
576 exit(1);
577 }
578
579 /*
580 * Check if cluster is running. A clean shutdown is required to avoid
581 * random checksum failures caused by torn pages. Note that this doesn't
582 * guard against someone starting the cluster concurrently.
583 */
586 pg_fatal("cluster must be shut down");
587
590 pg_fatal("data checksums are not enabled in cluster");
591
594 pg_fatal("data checksums are already disabled in cluster");
595
598 pg_fatal("data checksums are already enabled in cluster");
599
600 /* Operate on all files if checking or enabling checksums */
602 {
603 /*
604 * If progress status information is requested, we need to scan the
605 * directory tree twice: once to know how much total data needs to be
606 * processed and once to do the real work.
607 */
608 if (showprogress)
609 {
610 total_size = scan_directory(DataDir, "global", true);
611 total_size += scan_directory(DataDir, "base", true);
613 }
614
615 (void) scan_directory(DataDir, "global", false);
616 (void) scan_directory(DataDir, "base", false);
617 (void) scan_directory(DataDir, PG_TBLSPC_DIR, false);
618
619 if (showprogress)
620 progress_report(true);
621
622 printf(_("Checksum operation completed\n"));
623 printf(_("Files scanned: %" PRId64 "\n"), files_scanned);
624 printf(_("Blocks scanned: %" PRId64 "\n"), blocks_scanned);
625 if (mode == PG_MODE_CHECK)
626 {
627 printf(_("Bad checksums: %" PRId64 "\n"), badblocks);
628 printf(_("Data checksum version: %u\n"), ControlFile->data_checksum_version);
629
630 if (badblocks > 0)
631 exit(1);
632 }
633 else if (mode == PG_MODE_ENABLE)
634 {
635 printf(_("Files written: %" PRId64 "\n"), files_written);
636 printf(_("Blocks written: %" PRId64 "\n"), blocks_written);
637 }
638 }
639
640 /*
641 * Finally make the data durable on disk if enabling or disabling
642 * checksums. Flush first the data directory for safety, and then update
643 * the control file to keep the switch consistent.
644 */
646 {
649
650 if (do_sync)
651 {
652 pg_log_info("syncing data directory");
653 sync_pgdata(DataDir, PG_VERSION_NUM, sync_method, true);
654 }
655
656 pg_log_info("updating control file");
658
659 if (verbose)
660 printf(_("Data checksum version: %u\n"), ControlFile->data_checksum_version);
661 if (mode == PG_MODE_ENABLE)
662 printf(_("Checksums enabled in cluster\n"));
663 else
664 printf(_("Checksums disabled in cluster\n"));
665 }
666
667 return 0;
668}
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1609
uint32 BlockNumber
Definition: block.h:31
PageHeaderData * PageHeader
Definition: bufpage.h:173
static bool PageIsNew(const PageData *page)
Definition: bufpage.h:233
#define PG_DATA_CHECKSUM_VERSION
Definition: bufpage.h:206
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1214
int64_t int64
Definition: c.h:540
#define PG_BINARY
Definition: c.h:1273
uint16_t uint16
Definition: c.h:542
uint32_t uint32
Definition: c.h:543
uint16 pg_checksum_page(char *page, BlockNumber blkno)
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:430
void update_controlfile(const char *DataDir, ControlFileData *ControlFile, bool do_sync)
ControlFileData * get_controlfile(const char *DataDir, bool *crc_ok_p)
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
int closedir(DIR *)
Definition: dirent.c:127
struct dirent * readdir(DIR *)
Definition: dirent.c:78
DIR * opendir(const char *)
Definition: dirent.c:33
#define _(x)
Definition: elog.c:91
uint32 get_pg_version(const char *datadir, char **version_str)
Definition: version.c:44
#define PG_TEMP_FILES_DIR
Definition: file_utils.h:63
#define PG_TEMP_FILE_PREFIX
Definition: file_utils.h:64
DataDirSyncMethod
Definition: file_utils.h:28
@ DATA_DIR_SYNC_METHOD_FSYNC
Definition: file_utils.h:29
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define no_argument
Definition: getopt_long.h:25
#define required_argument
Definition: getopt_long.h:26
char * DataDir
Definition: globals.c:71
Assert(PointerIsAligned(start, uint64))
#define close(a)
Definition: win32.h:12
#define write(a, b, c)
Definition: win32.h:14
#define read(a, b, c)
Definition: win32.h:13
void pg_logging_init(const char *argv0)
Definition: logging.c:83
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_error_hint(...)
Definition: logging.h:112
#define pg_log_info(...)
Definition: logging.h:124
#define pg_log_error_detail(...)
Definition: logging.h:109
char * pstrdup(const char *in)
Definition: mcxt.c:1759
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
Definition: option_utils.c:50
bool parse_sync_method(const char *optarg, DataDirSyncMethod *sync_method)
Definition: option_utils.c:90
#define pg_fatal(...)
static char * basedir
int main(int argc, char *argv[])
Definition: pg_checksums.c:433
static void scan_file(const char *fn, int segmentno)
Definition: pg_checksums.c:176
static int64 total_size
Definition: pg_checksums.c:63
static PgChecksumMode mode
Definition: pg_checksums.c:56
static char * only_filenode
Definition: pg_checksums.c:43
static int64 blocks_scanned
Definition: pg_checksums.c:38
static int64 current_size
Definition: pg_checksums.c:64
static void progress_report(bool finished)
Definition: pg_checksums.c:124
static pg_time_t last_progress_report
Definition: pg_checksums.c:65
static const struct exclude_list_item skip[]
Definition: pg_checksums.c:108
static int64 scan_directory(const char *basedir, const char *subdir, bool sizeonly)
Definition: pg_checksums.c:300
static int64 files_scanned
Definition: pg_checksums.c:36
static bool do_sync
Definition: pg_checksums.c:44
static bool verbose
Definition: pg_checksums.c:45
static bool skipfile(const char *fn)
Definition: pg_checksums.c:158
static ControlFileData * ControlFile
Definition: pg_checksums.c:41
static DataDirSyncMethod sync_method
Definition: pg_checksums.c:47
static int64 blocks_written
Definition: pg_checksums.c:39
static bool showprogress
Definition: pg_checksums.c:46
static const char * progname
Definition: pg_checksums.c:58
static void usage(void)
Definition: pg_checksums.c:68
static int64 files_written
Definition: pg_checksums.c:37
PgChecksumMode
Definition: pg_checksums.c:50
@ PG_MODE_CHECK
Definition: pg_checksums.c:51
@ PG_MODE_DISABLE
Definition: pg_checksums.c:52
@ PG_MODE_ENABLE
Definition: pg_checksums.c:53
static int64 badblocks
Definition: pg_checksums.c:40
#define MAXPGPATH
#define PG_CONTROL_VERSION
Definition: pg_control.h:25
@ DB_SHUTDOWNED_IN_RECOVERY
Definition: pg_control.h:93
@ DB_SHUTDOWNED
Definition: pg_control.h:92
PGDLLIMPORT int optind
Definition: getopt.c:51
PGDLLIMPORT char * optarg
Definition: getopt.c:53
static char * buf
Definition: pg_test_fsync.c:72
int64 pg_time_t
Definition: pgtime.h:23
#define snprintf
Definition: port.h:239
const char * get_progname(const char *argv0)
Definition: path.c:652
#define printf(...)
Definition: port.h:245
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char * c
#define PG_TBLSPC_DIR
Definition: relpath.h:41
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
uint32 pg_control_version
Definition: pg_control.h:125
uint32 data_checksum_version
Definition: pg_control.h:224
Definition: dirent.c:26
uint16 pd_checksum
Definition: bufpage.h:163
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
const char * name
Definition: basebackup.c:139
__int64 st_size
Definition: win32_port.h:263
unsigned short st_mode
Definition: win32_port.h:258
static void * fn(void *arg)
Definition: thread-alloc.c:119
#define GET_PG_MAJORVERSION_NUM(v)
Definition: version.h:19
const char * name
#define lstat(path, sb)
Definition: win32_port.h:275
#define S_ISDIR(m)
Definition: win32_port.h:315
#define S_ISLNK(m)
Definition: win32_port.h:334
#define S_ISREG(m)
Definition: win32_port.h:318