PostgreSQL Source Code git master
Loading...
Searching...
No Matches
file_ops.c File Reference
#include "postgres_fe.h"
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include "common/file_perm.h"
#include "common/file_utils.h"
#include "file_ops.h"
#include "filemap.h"
#include "pg_rewind.h"
Include dependency graph for file_ops.c:

Go to the source code of this file.

Functions

static void create_target_dir (const char *path)
 
static void remove_target_dir (const char *path)
 
static void create_target_symlink (const char *path, const char *link)
 
static void remove_target_symlink (const char *path)
 
static void recurse_dir (const char *datadir, const char *parentpath, process_file_callback_t callback)
 
void open_target_file (const char *path, bool trunc)
 
void close_target_file (void)
 
void write_target_range (char *buf, off_t begin, size_t size)
 
void remove_target (file_entry_t *entry)
 
void create_target (file_entry_t *entry)
 
void remove_target_file (const char *path, bool missing_ok)
 
void truncate_target_file (const char *path, off_t newsize)
 
void sync_target_dir (void)
 
charslurpFile (const char *datadir, const char *path, size_t *filesize)
 
void traverse_datadir (const char *datadir, process_file_callback_t callback)
 

Variables

static int dstfd = -1
 
static char dstpath [MAXPGPATH] = ""
 

Function Documentation

◆ close_target_file()

void close_target_file ( void  )

Definition at line 78 of file file_ops.c.

79{
80 if (dstfd == -1)
81 return;
82
83 if (close(dstfd) != 0)
84 pg_fatal("could not close target file \"%s\": %m",
85 dstpath);
86
87 dstfd = -1;
88}
static char dstpath[MAXPGPATH]
Definition file_ops.c:32
static int dstfd
Definition file_ops.c:31
#define close(a)
Definition win32.h:12
#define pg_fatal(...)

References close, dstfd, dstpath, and pg_fatal.

Referenced by createBackupLabel(), open_target_file(), and perform_rewind().

◆ create_target()

void create_target ( file_entry_t entry)

Definition at line 159 of file file_ops.c.

160{
162 Assert(!entry->target_exists);
163
164 switch (entry->source_type)
165 {
167 create_target_dir(entry->path);
168 break;
169
172 break;
173
175 /* can't happen. Regular files are created with open_target_file. */
176 pg_fatal("invalid action (CREATE) for regular file");
177 break;
178
180 pg_fatal("undefined file type for \"%s\"", entry->path);
181 break;
182 }
183}
#define Assert(condition)
Definition c.h:943
static void create_target_symlink(const char *path, const char *link)
Definition file_ops.c:274
static void create_target_dir(const char *path)
Definition file_ops.c:238
@ FILE_ACTION_CREATE
Definition filemap.h:21
@ FILE_TYPE_UNDEFINED
Definition filemap.h:33
@ FILE_TYPE_REGULAR
Definition filemap.h:35
@ FILE_TYPE_SYMLINK
Definition filemap.h:37
@ FILE_TYPE_DIRECTORY
Definition filemap.h:36
const char * path
Definition filemap.h:61
bool target_exists
Definition filemap.h:67
char * source_link_target
Definition filemap.h:84
file_type_t source_type
Definition filemap.h:82
file_action_t action
Definition filemap.h:89

References file_entry_t::action, Assert, create_target_dir(), create_target_symlink(), FILE_ACTION_CREATE, FILE_TYPE_DIRECTORY, FILE_TYPE_REGULAR, FILE_TYPE_SYMLINK, FILE_TYPE_UNDEFINED, file_entry_t::path, pg_fatal, file_entry_t::source_link_target, file_entry_t::source_type, and file_entry_t::target_exists.

Referenced by perform_rewind().

◆ create_target_dir()

static void create_target_dir ( const char path)
static

Definition at line 238 of file file_ops.c.

239{
240 char dstpath[MAXPGPATH];
241
243 pg_fatal("target directory path is unsafe for directory creation: \"%s\"",
244 path);
245
246 if (dry_run)
247 return;
248
249 snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
251 pg_fatal("could not create directory \"%s\": %m",
252 dstpath);
253}
int pg_dir_create_mode
Definition file_perm.c:18
#define MAXPGPATH
static bool dry_run
char * datadir_target
Definition pg_rewind.c:67
bool path_is_safe_for_extraction(const char *path)
Definition path.c:637
#define snprintf
Definition port.h:261
#define mkdir(a, b)
Definition win32_port.h:80

References datadir_target, dry_run, dstpath, MAXPGPATH, mkdir, path_is_safe_for_extraction(), pg_dir_create_mode, pg_fatal, and snprintf.

Referenced by create_target().

◆ create_target_symlink()

static void create_target_symlink ( const char path,
const char link 
)
static

Definition at line 274 of file file_ops.c.

275{
276 char dstpath[MAXPGPATH];
277
279 pg_fatal("target symlink path is unsafe for creation: \"%s\"", path);
280
281 if (dry_run)
282 return;
283
284 snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
285 if (symlink(link, dstpath) != 0)
286 pg_fatal("could not create symbolic link at \"%s\": %m",
287 dstpath);
288}
#define symlink(oldpath, newpath)
Definition win32_port.h:225

References datadir_target, dry_run, dstpath, MAXPGPATH, path_is_safe_for_extraction(), pg_fatal, snprintf, and symlink.

Referenced by create_target().

◆ open_target_file()

void open_target_file ( const char path,
bool  trunc 
)

Definition at line 47 of file file_ops.c.

48{
49 int mode;
50
52 pg_fatal("target file path is unsafe for open: \"%s\"", path);
53
54 if (dry_run)
55 return;
56
57 if (dstfd != -1 && !trunc &&
58 strcmp(path, &dstpath[strlen(datadir_target) + 1]) == 0)
59 return; /* already open */
60
62
63 snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
64
66 if (trunc)
67 mode |= O_TRUNC;
69 if (dstfd < 0)
70 pg_fatal("could not open target file \"%s\": %m",
71 dstpath);
72}
#define PG_BINARY
Definition c.h:1374
void close_target_file(void)
Definition file_ops.c:78
int pg_file_create_mode
Definition file_perm.c:19
static PgChecksumMode mode
static int fb(int x)

References close_target_file(), datadir_target, dry_run, dstfd, dstpath, fb(), mode, path_is_safe_for_extraction(), PG_BINARY, pg_fatal, pg_file_create_mode, and snprintf.

Referenced by createBackupLabel(), libpq_queue_fetch_file(), local_queue_fetch_file(), local_queue_fetch_range(), and process_queued_fetch_requests().

◆ recurse_dir()

static void recurse_dir ( const char datadir,
const char parentpath,
process_file_callback_t  callback 
)
static

Definition at line 397 of file file_ops.c.

399{
400 DIR *xldir;
401 struct dirent *xlde;
403
404 if (parentpath)
406 else
408
410 if (xldir == NULL)
411 pg_fatal("could not open directory \"%s\": %m",
413
414 while (errno = 0, (xlde = readdir(xldir)) != NULL)
415 {
416 struct stat fst;
417 char fullpath[MAXPGPATH * 2];
418 char path[MAXPGPATH * 2];
419
420 if (strcmp(xlde->d_name, ".") == 0 ||
421 strcmp(xlde->d_name, "..") == 0)
422 continue;
423
424 snprintf(fullpath, sizeof(fullpath), "%s/%s", fullparentpath, xlde->d_name);
425
426 if (lstat(fullpath, &fst) < 0)
427 {
428 if (errno == ENOENT)
429 {
430 /*
431 * File doesn't exist anymore. This is ok, if the new primary
432 * is running and the file was just removed. If it was a data
433 * file, there should be a WAL record of the removal. If it
434 * was something else, it couldn't have been anyway.
435 *
436 * TODO: But complain if we're processing the target dir!
437 */
438 }
439 else
440 pg_fatal("could not stat file \"%s\": %m",
441 fullpath);
442 }
443
444 if (parentpath)
445 snprintf(path, sizeof(path), "%s/%s", parentpath, xlde->d_name);
446 else
447 snprintf(path, sizeof(path), "%s", xlde->d_name);
448
449 if (S_ISREG(fst.st_mode))
450 callback(path, FILE_TYPE_REGULAR, fst.st_size, NULL);
451 else if (S_ISDIR(fst.st_mode))
452 {
454 /* recurse to handle subdirectories */
456 }
457 else if (S_ISLNK(fst.st_mode))
458 {
460 int len;
461
462 len = readlink(fullpath, link_target, sizeof(link_target));
463 if (len < 0)
464 pg_fatal("could not read symbolic link \"%s\": %m",
465 fullpath);
466 if (len >= sizeof(link_target))
467 pg_fatal("symbolic link \"%s\" target is too long",
468 fullpath);
469 link_target[len] = '\0';
470
472
473 /*
474 * If it's a symlink within pg_tblspc, we need to recurse into it,
475 * to process all the tablespaces. We also follow a symlink if
476 * it's for pg_wal. Symlinks elsewhere are ignored.
477 */
478 if ((parentpath && strcmp(parentpath, PG_TBLSPC_DIR) == 0) ||
479 strcmp(path, "pg_wal") == 0)
481 }
482 }
483
484 if (errno)
485 pg_fatal("could not read directory \"%s\": %m",
487
488 if (closedir(xldir))
489 pg_fatal("could not close directory \"%s\": %m",
491}
int closedir(DIR *)
Definition dirent.c:127
struct dirent * readdir(DIR *)
Definition dirent.c:78
DIR * opendir(const char *)
Definition dirent.c:33
static void recurse_dir(const char *datadir, const char *parentpath, process_file_callback_t callback)
Definition file_ops.c:397
const void size_t len
char * datadir
#define PG_TBLSPC_DIR
Definition relpath.h:41
Definition dirent.c:26
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
#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 readlink(path, buf, size)
Definition win32_port.h:226
#define S_ISREG(m)
Definition win32_port.h:318

References callback(), closedir(), datadir, fb(), FILE_TYPE_DIRECTORY, FILE_TYPE_REGULAR, FILE_TYPE_SYMLINK, len, lstat, MAXPGPATH, opendir(), pg_fatal, PG_TBLSPC_DIR, readdir(), readlink, recurse_dir(), S_ISDIR, S_ISLNK, S_ISREG, and snprintf.

Referenced by recurse_dir(), and traverse_datadir().

◆ remove_target()

void remove_target ( file_entry_t entry)

Definition at line 133 of file file_ops.c.

134{
136 Assert(entry->target_exists);
137
138 switch (entry->target_type)
139 {
141 remove_target_dir(entry->path);
142 break;
143
145 remove_target_file(entry->path, false);
146 break;
147
150 break;
151
153 pg_fatal("undefined file type for \"%s\"", entry->path);
154 break;
155 }
156}
void remove_target_file(const char *path, bool missing_ok)
Definition file_ops.c:190
static void remove_target_dir(const char *path)
Definition file_ops.c:256
static void remove_target_symlink(const char *path)
Definition file_ops.c:291
@ FILE_ACTION_REMOVE
Definition filemap.h:28
file_type_t target_type
Definition filemap.h:68

References file_entry_t::action, Assert, FILE_ACTION_REMOVE, FILE_TYPE_DIRECTORY, FILE_TYPE_REGULAR, FILE_TYPE_SYMLINK, FILE_TYPE_UNDEFINED, file_entry_t::path, pg_fatal, remove_target_dir(), remove_target_file(), remove_target_symlink(), file_entry_t::target_exists, and file_entry_t::target_type.

Referenced by perform_rewind().

◆ remove_target_dir()

static void remove_target_dir ( const char path)
static

Definition at line 256 of file file_ops.c.

257{
258 char dstpath[MAXPGPATH];
259
261 pg_fatal("target directory path is unsafe for directory removal: \"%s\"",
262 path);
263
264 if (dry_run)
265 return;
266
267 snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
268 if (rmdir(dstpath) != 0)
269 pg_fatal("could not remove directory \"%s\": %m",
270 dstpath);
271}

References datadir_target, dry_run, dstpath, fb(), MAXPGPATH, path_is_safe_for_extraction(), pg_fatal, and snprintf.

Referenced by remove_target().

◆ remove_target_file()

void remove_target_file ( const char path,
bool  missing_ok 
)

Definition at line 190 of file file_ops.c.

191{
192 char dstpath[MAXPGPATH];
193
195 pg_fatal("target file path is unsafe for removal: \"%s\"", path);
196
197 if (dry_run)
198 return;
199
200 snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
201 if (unlink(dstpath) != 0)
202 {
203 if (errno == ENOENT && missing_ok)
204 return;
205
206 pg_fatal("could not remove file \"%s\": %m",
207 dstpath);
208 }
209}

References datadir_target, dry_run, dstpath, fb(), MAXPGPATH, path_is_safe_for_extraction(), pg_fatal, and snprintf.

Referenced by process_queued_fetch_requests(), and remove_target().

◆ remove_target_symlink()

static void remove_target_symlink ( const char path)
static

Definition at line 291 of file file_ops.c.

292{
293 char dstpath[MAXPGPATH];
294
296 pg_fatal("target symlink path is unsafe for removal: \"%s\"", path);
297
298 if (dry_run)
299 return;
300
301 snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
302 if (unlink(dstpath) != 0)
303 pg_fatal("could not remove symbolic link \"%s\": %m",
304 dstpath);
305}

References datadir_target, dry_run, dstpath, fb(), MAXPGPATH, path_is_safe_for_extraction(), pg_fatal, and snprintf.

Referenced by remove_target().

◆ slurpFile()

char * slurpFile ( const char datadir,
const char path,
size_t filesize 
)

Definition at line 337 of file file_ops.c.

338{
339 int fd;
340 char *buffer;
341 struct stat statbuf;
342 char fullpath[MAXPGPATH];
343 int len;
344 int r;
345
346 snprintf(fullpath, sizeof(fullpath), "%s/%s", datadir, path);
347
348 if ((fd = open(fullpath, O_RDONLY | PG_BINARY, 0)) == -1)
349 pg_fatal("could not open file \"%s\" for reading: %m",
350 fullpath);
351
352 if (fstat(fd, &statbuf) < 0)
353 pg_fatal("could not stat file \"%s\": %m",
354 fullpath);
355
356 len = statbuf.st_size;
357
358 buffer = pg_malloc(len + 1);
359
360 r = read(fd, buffer, len);
361 if (r != len)
362 {
363 if (r < 0)
364 pg_fatal("could not read file \"%s\": %m",
365 fullpath);
366 else
367 pg_fatal("could not read file \"%s\": read %d of %zu",
368 fullpath, r, (Size) len);
369 }
370 close(fd);
371
372 /* Zero-terminate the buffer. */
373 buffer[len] = '\0';
374
375 if (filesize)
376 *filesize = len;
377 return buffer;
378}
size_t Size
Definition c.h:689
void * pg_malloc(size_t size)
Definition fe_memutils.c:53
#define read(a, b, c)
Definition win32.h:13
static int fd(const char *x, int i)
#define fstat
Definition win32_port.h:73

References close, datadir, fb(), fd(), fstat, len, MAXPGPATH, PG_BINARY, pg_fatal, pg_malloc(), read, and snprintf.

Referenced by getTimelineHistory(), local_fetch_file(), and main().

◆ sync_target_dir()

void sync_target_dir ( void  )

Definition at line 317 of file file_ops.c.

318{
319 if (!do_sync || dry_run)
320 return;
321
323}
static bool do_sync
Definition initdb.c:164
static DataDirSyncMethod sync_method
Definition initdb.c:170

References datadir_target, do_sync, dry_run, fb(), and sync_method.

Referenced by main().

◆ traverse_datadir()

void traverse_datadir ( const char datadir,
process_file_callback_t  callback 
)

Definition at line 385 of file file_ops.c.

386{
388}

References callback(), datadir, fb(), and recurse_dir().

Referenced by local_traverse_files(), and main().

◆ truncate_target_file()

void truncate_target_file ( const char path,
off_t  newsize 
)

Definition at line 212 of file file_ops.c.

213{
214 char dstpath[MAXPGPATH];
215 int fd;
216
218 pg_fatal("target file path is unsafe for truncation: \"%s\"", path);
219
220 if (dry_run)
221 return;
222
223 snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
224
226 if (fd < 0)
227 pg_fatal("could not open file \"%s\" for truncation: %m",
228 dstpath);
229
230 if (ftruncate(fd, newsize) != 0)
231 pg_fatal("could not truncate file \"%s\" to %u: %m",
232 dstpath, (unsigned int) newsize);
233
234 close(fd);
235}

References close, datadir_target, dry_run, dstpath, fb(), fd(), MAXPGPATH, path_is_safe_for_extraction(), pg_fatal, pg_file_create_mode, and snprintf.

Referenced by perform_rewind().

◆ write_target_range()

void write_target_range ( char buf,
off_t  begin,
size_t  size 
)

Definition at line 91 of file file_ops.c.

92{
93 size_t writeleft;
94 char *p;
95
96 /* update progress report */
97 fetch_done += size;
98 progress_report(false);
99
100 if (dry_run)
101 return;
102
103 if (lseek(dstfd, begin, SEEK_SET) == -1)
104 pg_fatal("could not seek in target file \"%s\": %m",
105 dstpath);
106
107 writeleft = size;
108 p = buf;
109 while (writeleft > 0)
110 {
112
113 errno = 0;
115 if (writelen < 0)
116 {
117 /* if write didn't set errno, assume problem is no disk space */
118 if (errno == 0)
119 errno = ENOSPC;
120 pg_fatal("could not write file \"%s\": %m",
121 dstpath);
122 }
123
124 p += writelen;
126 }
127
128 /* keep the file open, in case we need to copy more blocks in it */
129}
#define write(a, b, c)
Definition win32.h:14
static void progress_report(uint64 relations_total, uint64 relations_checked, uint64 relpages_total, uint64 relpages_checked, const char *datname, bool force, bool finished)
uint64 fetch_done
Definition pg_rewind.c:86
static char buf[DEFAULT_XLOG_SEG_SIZE]

References buf, dry_run, dstfd, dstpath, fb(), fetch_done, pg_fatal, progress_report(), and write.

Referenced by createBackupLabel(), local_queue_fetch_file(), local_queue_fetch_range(), and process_queued_fetch_requests().

Variable Documentation

◆ dstfd

int dstfd = -1
static

◆ dstpath