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-2024, 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 <time.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 
24 #include "common/file_perm.h"
25 #include "common/file_utils.h"
26 #include "common/logging.h"
27 #include "common/relpath.h"
28 #include "fe_utils/option_utils.h"
29 #include "getopt_long.h"
30 #include "pg_getopt.h"
31 #include "storage/bufpage.h"
32 #include "storage/checksum.h"
33 #include "storage/checksum_impl.h"
34 
35 
36 static int64 files_scanned = 0;
37 static int64 files_written = 0;
38 static int64 blocks_scanned = 0;
39 static int64 blocks_written = 0;
40 static int64 badblocks = 0;
42 
43 static char *only_filenode = NULL;
44 static bool do_sync = true;
45 static bool verbose = false;
46 static bool showprogress = false;
48 
49 typedef enum
50 {
55 
57 
58 static const char *progname;
59 
60 /*
61  * Progress status information.
62  */
63 static int64 total_size = 0;
64 static int64 current_size = 0;
66 
67 static void
68 usage(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  */
97 struct exclude_list_item
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  */
108 static 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  */
123 static void
124 progress_report(bool finished)
125 {
126  int percent;
127  pg_time_t now;
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 */
139  if (current_size > total_size)
141 
142  /* Calculate current percentage of size done */
143  percent = total_size ? (int) ((current_size) * 100 / total_size) : 0;
144 
145  fprintf(stderr, _("%lld/%lld MB (%d%%) computed"),
146  (long long) (current_size / (1024 * 1024)),
147  (long long) (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 
157 static bool
158 skipfile(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 
175 static void
176 scan_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 
186  mode == PG_MODE_CHECK);
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 
194  files_scanned++;
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  }
212  blocks_scanned++;
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  {
285  files_written++;
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  */
299 static int64
300 scan_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", subdir, strlen("pg_tblspc")) == 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 
432 int
433 main(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 
453  pg_logging_init(argv[0]);
454  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_checksums"));
455  progname = get_progname(argv[0]);
456 
457  if (argc > 1)
458  {
459  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
460  {
461  usage();
462  exit(0);
463  }
464  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
465  {
466  puts("pg_checksums (PostgreSQL) " PG_VERSION);
467  exit(0);
468  }
469  }
470 
471  while ((c = getopt_long(argc, argv, "cdD:ef:NPv", long_options, &option_index)) != -1)
472  {
473  switch (c)
474  {
475  case 'c':
477  break;
478  case 'd':
480  break;
481  case 'D':
482  DataDir = optarg;
483  break;
484  case 'e':
486  break;
487  case 'f':
488  if (!option_parse_int(optarg, "-f/--filenode", 0,
489  INT_MAX,
490  NULL))
491  exit(1);
493  break;
494  case 'N':
495  do_sync = false;
496  break;
497  case 'P':
498  showprogress = true;
499  break;
500  case 'v':
501  verbose = true;
502  break;
503  case 1:
505  exit(1);
506  break;
507  default:
508  /* getopt_long already emitted a complaint */
509  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
510  exit(1);
511  }
512  }
513 
514  if (DataDir == NULL)
515  {
516  if (optind < argc)
517  DataDir = argv[optind++];
518  else
519  DataDir = getenv("PGDATA");
520 
521  /* If no DataDir was specified, and none could be found, error out */
522  if (DataDir == NULL)
523  {
524  pg_log_error("no data directory specified");
525  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
526  exit(1);
527  }
528  }
529 
530  /* Complain if any arguments remain */
531  if (optind < argc)
532  {
533  pg_log_error("too many command-line arguments (first is \"%s\")",
534  argv[optind]);
535  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
536  exit(1);
537  }
538 
539  /* filenode checking only works in --check mode */
540  if (mode != PG_MODE_CHECK && only_filenode)
541  {
542  pg_log_error("option -f/--filenode can only be used with --check");
543  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
544  exit(1);
545  }
546 
547  /* Read the control file and check compatibility */
548  ControlFile = get_controlfile(DataDir, &crc_ok);
549  if (!crc_ok)
550  pg_fatal("pg_control CRC value is incorrect");
551 
553  pg_fatal("cluster is not compatible with this version of pg_checksums");
554 
555  if (ControlFile->blcksz != BLCKSZ)
556  {
557  pg_log_error("database cluster is not compatible");
558  pg_log_error_detail("The database cluster was initialized with block size %u, but pg_checksums was compiled with block size %u.",
559  ControlFile->blcksz, BLCKSZ);
560  exit(1);
561  }
562 
563  /*
564  * Check if cluster is running. A clean shutdown is required to avoid
565  * random checksum failures caused by torn pages. Note that this doesn't
566  * guard against someone starting the cluster concurrently.
567  */
568  if (ControlFile->state != DB_SHUTDOWNED &&
570  pg_fatal("cluster must be shut down");
571 
573  mode == PG_MODE_CHECK)
574  pg_fatal("data checksums are not enabled in cluster");
575 
578  pg_fatal("data checksums are already disabled in cluster");
579 
581  mode == PG_MODE_ENABLE)
582  pg_fatal("data checksums are already enabled in cluster");
583 
584  /* Operate on all files if checking or enabling checksums */
585  if (mode == PG_MODE_CHECK || mode == PG_MODE_ENABLE)
586  {
587  /*
588  * If progress status information is requested, we need to scan the
589  * directory tree twice: once to know how much total data needs to be
590  * processed and once to do the real work.
591  */
592  if (showprogress)
593  {
594  total_size = scan_directory(DataDir, "global", true);
595  total_size += scan_directory(DataDir, "base", true);
596  total_size += scan_directory(DataDir, "pg_tblspc", true);
597  }
598 
599  (void) scan_directory(DataDir, "global", false);
600  (void) scan_directory(DataDir, "base", false);
601  (void) scan_directory(DataDir, "pg_tblspc", false);
602 
603  if (showprogress)
604  progress_report(true);
605 
606  printf(_("Checksum operation completed\n"));
607  printf(_("Files scanned: %lld\n"), (long long) files_scanned);
608  printf(_("Blocks scanned: %lld\n"), (long long) blocks_scanned);
609  if (mode == PG_MODE_CHECK)
610  {
611  printf(_("Bad checksums: %lld\n"), (long long) badblocks);
612  printf(_("Data checksum version: %u\n"), ControlFile->data_checksum_version);
613 
614  if (badblocks > 0)
615  exit(1);
616  }
617  else if (mode == PG_MODE_ENABLE)
618  {
619  printf(_("Files written: %lld\n"), (long long) files_written);
620  printf(_("Blocks written: %lld\n"), (long long) blocks_written);
621  }
622  }
623 
624  /*
625  * Finally make the data durable on disk if enabling or disabling
626  * checksums. Flush first the data directory for safety, and then update
627  * the control file to keep the switch consistent.
628  */
630  {
633 
634  if (do_sync)
635  {
636  pg_log_info("syncing data directory");
637  sync_pgdata(DataDir, PG_VERSION_NUM, sync_method);
638  }
639 
640  pg_log_info("updating control file");
642 
643  if (verbose)
644  printf(_("Data checksum version: %u\n"), ControlFile->data_checksum_version);
645  if (mode == PG_MODE_ENABLE)
646  printf(_("Checksums enabled in cluster\n"));
647  else
648  printf(_("Checksums disabled in cluster\n"));
649  }
650 
651  return 0;
652 }
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1619
uint32 BlockNumber
Definition: block.h:31
PageHeaderData * PageHeader
Definition: bufpage.h:170
static bool PageIsNew(Page page)
Definition: bufpage.h:230
#define PG_DATA_CHECKSUM_VERSION
Definition: bufpage.h:203
unsigned short uint16
Definition: c.h:505
#define Assert(condition)
Definition: c.h:858
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1214
#define PG_BINARY
Definition: c.h:1273
uint16 pg_checksum_page(char *page, BlockNumber blkno)
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:448
void update_controlfile(const char *DataDir, ControlFileData *ControlFile, bool do_sync)
ControlFileData * get_controlfile(const char *DataDir, bool *crc_ok_p)
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:90
#define PG_TEMP_FILES_DIR
Definition: file_utils.h:62
#define PG_TEMP_FILE_PREFIX
Definition: file_utils.h:63
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:24
#define required_argument
Definition: getopt_long.h:25
char * DataDir
Definition: globals.c:69
#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
exit(1)
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:1696
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:92
@ DB_SHUTDOWNED
Definition: pg_control.h:91
PGDLLIMPORT int optind
Definition: getopt.c:50
PGDLLIMPORT char * optarg
Definition: getopt.c:52
static char * buf
Definition: pg_test_fsync.c:73
int64 pg_time_t
Definition: pgtime.h:23
const char * get_progname(const char *argv0)
Definition: path.c:574
#define snprintf
Definition: port.h:238
#define fprintf
Definition: port.h:242
#define printf(...)
Definition: port.h:244
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char * c
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
uint32 pg_control_version
Definition: pg_control.h:124
uint32 data_checksum_version
Definition: pg_control.h:221
Definition: dirent.c:26
uint16 pd_checksum
Definition: bufpage.h:160
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:273
unsigned short st_mode
Definition: win32_port.h:268
static void * fn(void *arg)
Definition: thread-alloc.c:119
const char * name
#define lstat(path, sb)
Definition: win32_port.h:285
#define S_ISDIR(m)
Definition: win32_port.h:325
#define S_ISLNK(m)
Definition: win32_port.h:344
#define S_ISREG(m)
Definition: win32_port.h:328