PostgreSQL Source Code  git master
file_ops.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * file_ops.c
4  * Helper functions for operating on files.
5  *
6  * Most of the functions in this file are helper functions for writing to
7  * the target data directory. The functions check the --dry-run flag, and
8  * do nothing if it's enabled. You should avoid accessing the target files
9  * directly but if you do, make sure you honor the --dry-run mode!
10  *
11  * Portions Copyright (c) 2013-2019, PostgreSQL Global Development Group
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres_fe.h"
16 
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 
21 #include "common/file_perm.h"
22 #include "file_ops.h"
23 #include "filemap.h"
24 #include "pg_rewind.h"
25 
26 /*
27  * Currently open target file.
28  */
29 static int dstfd = -1;
30 static char dstpath[MAXPGPATH] = "";
31 
32 static void create_target_dir(const char *path);
33 static void remove_target_dir(const char *path);
34 static void create_target_symlink(const char *path, const char *link);
35 static void remove_target_symlink(const char *path);
36 
37 /*
38  * Open a target file for writing. If 'trunc' is true and the file already
39  * exists, it will be truncated.
40  */
41 void
42 open_target_file(const char *path, bool trunc)
43 {
44  int mode;
45 
46  if (dry_run)
47  return;
48 
49  if (dstfd != -1 && !trunc &&
50  strcmp(path, &dstpath[strlen(datadir_target) + 1]) == 0)
51  return; /* already open */
52 
54 
55  snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
56 
57  mode = O_WRONLY | O_CREAT | PG_BINARY;
58  if (trunc)
59  mode |= O_TRUNC;
60  dstfd = open(dstpath, mode, pg_file_create_mode);
61  if (dstfd < 0)
62  pg_fatal("could not open target file \"%s\": %m",
63  dstpath);
64 }
65 
66 /*
67  * Close target file, if it's open.
68  */
69 void
71 {
72  if (dstfd == -1)
73  return;
74 
75  if (close(dstfd) != 0)
76  pg_fatal("could not close target file \"%s\": %m",
77  dstpath);
78 
79  dstfd = -1;
80 }
81 
82 void
83 write_target_range(char *buf, off_t begin, size_t size)
84 {
85  int writeleft;
86  char *p;
87 
88  /* update progress report */
89  fetch_done += size;
90  progress_report(false);
91 
92  if (dry_run)
93  return;
94 
95  if (lseek(dstfd, begin, SEEK_SET) == -1)
96  pg_fatal("could not seek in target file \"%s\": %m",
97  dstpath);
98 
99  writeleft = size;
100  p = buf;
101  while (writeleft > 0)
102  {
103  int writelen;
104 
105  errno = 0;
106  writelen = write(dstfd, p, writeleft);
107  if (writelen < 0)
108  {
109  /* if write didn't set errno, assume problem is no disk space */
110  if (errno == 0)
111  errno = ENOSPC;
112  pg_fatal("could not write file \"%s\": %m",
113  dstpath);
114  }
115 
116  p += writelen;
117  writeleft -= writelen;
118  }
119 
120  /* keep the file open, in case we need to copy more blocks in it */
121 }
122 
123 
124 void
126 {
127  Assert(entry->action == FILE_ACTION_REMOVE);
128 
129  switch (entry->type)
130  {
131  case FILE_TYPE_DIRECTORY:
132  remove_target_dir(entry->path);
133  break;
134 
135  case FILE_TYPE_REGULAR:
136  remove_target_file(entry->path, false);
137  break;
138 
139  case FILE_TYPE_SYMLINK:
140  remove_target_symlink(entry->path);
141  break;
142  }
143 }
144 
145 void
147 {
148  Assert(entry->action == FILE_ACTION_CREATE);
149 
150  switch (entry->type)
151  {
152  case FILE_TYPE_DIRECTORY:
153  create_target_dir(entry->path);
154  break;
155 
156  case FILE_TYPE_SYMLINK:
157  create_target_symlink(entry->path, entry->link_target);
158  break;
159 
160  case FILE_TYPE_REGULAR:
161  /* can't happen. Regular files are created with open_target_file. */
162  pg_fatal("invalid action (CREATE) for regular file");
163  break;
164  }
165 }
166 
167 /*
168  * Remove a file from target data directory. If missing_ok is true, it
169  * is fine for the target file to not exist.
170  */
171 void
172 remove_target_file(const char *path, bool missing_ok)
173 {
174  char dstpath[MAXPGPATH];
175 
176  if (dry_run)
177  return;
178 
179  snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
180  if (unlink(dstpath) != 0)
181  {
182  if (errno == ENOENT && missing_ok)
183  return;
184 
185  pg_fatal("could not remove file \"%s\": %m",
186  dstpath);
187  }
188 }
189 
190 void
191 truncate_target_file(const char *path, off_t newsize)
192 {
193  char dstpath[MAXPGPATH];
194  int fd;
195 
196  if (dry_run)
197  return;
198 
199  snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
200 
201  fd = open(dstpath, O_WRONLY, pg_file_create_mode);
202  if (fd < 0)
203  pg_fatal("could not open file \"%s\" for truncation: %m",
204  dstpath);
205 
206  if (ftruncate(fd, newsize) != 0)
207  pg_fatal("could not truncate file \"%s\" to %u: %m",
208  dstpath, (unsigned int) newsize);
209 
210  close(fd);
211 }
212 
213 static void
214 create_target_dir(const char *path)
215 {
216  char dstpath[MAXPGPATH];
217 
218  if (dry_run)
219  return;
220 
221  snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
222  if (mkdir(dstpath, pg_dir_create_mode) != 0)
223  pg_fatal("could not create directory \"%s\": %m",
224  dstpath);
225 }
226 
227 static void
228 remove_target_dir(const char *path)
229 {
230  char dstpath[MAXPGPATH];
231 
232  if (dry_run)
233  return;
234 
235  snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
236  if (rmdir(dstpath) != 0)
237  pg_fatal("could not remove directory \"%s\": %m",
238  dstpath);
239 }
240 
241 static void
242 create_target_symlink(const char *path, const char *link)
243 {
244  char dstpath[MAXPGPATH];
245 
246  if (dry_run)
247  return;
248 
249  snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
250  if (symlink(link, dstpath) != 0)
251  pg_fatal("could not create symbolic link at \"%s\": %m",
252  dstpath);
253 }
254 
255 static void
256 remove_target_symlink(const char *path)
257 {
258  char dstpath[MAXPGPATH];
259 
260  if (dry_run)
261  return;
262 
263  snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
264  if (unlink(dstpath) != 0)
265  pg_fatal("could not remove symbolic link \"%s\": %m",
266  dstpath);
267 }
268 
269 
270 /*
271  * Read a file into memory. The file to be read is <datadir>/<path>.
272  * The file contents are returned in a malloc'd buffer, and *filesize
273  * is set to the length of the file.
274  *
275  * The returned buffer is always zero-terminated; the size of the returned
276  * buffer is actually *filesize + 1. That's handy when reading a text file.
277  * This function can be used to read binary files as well, you can just
278  * ignore the zero-terminator in that case.
279  *
280  * This function is used to implement the fetchFile function in the "fetch"
281  * interface (see fetch.c), but is also called directly.
282  */
283 char *
284 slurpFile(const char *datadir, const char *path, size_t *filesize)
285 {
286  int fd;
287  char *buffer;
288  struct stat statbuf;
289  char fullpath[MAXPGPATH];
290  int len;
291  int r;
292 
293  snprintf(fullpath, sizeof(fullpath), "%s/%s", datadir, path);
294 
295  if ((fd = open(fullpath, O_RDONLY | PG_BINARY, 0)) == -1)
296  pg_fatal("could not open file \"%s\" for reading: %m",
297  fullpath);
298 
299  if (fstat(fd, &statbuf) < 0)
300  pg_fatal("could not open file \"%s\" for reading: %m",
301  fullpath);
302 
303  len = statbuf.st_size;
304 
305  buffer = pg_malloc(len + 1);
306 
307  r = read(fd, buffer, len);
308  if (r != len)
309  {
310  if (r < 0)
311  pg_fatal("could not read file \"%s\": %m",
312  fullpath);
313  else
314  pg_fatal("could not read file \"%s\": read %d of %zu",
315  fullpath, r, (Size) len);
316  }
317  close(fd);
318 
319  /* Zero-terminate the buffer. */
320  buffer[len] = '\0';
321 
322  if (filesize)
323  *filesize = len;
324  return buffer;
325 }
static PgChecksumMode mode
Definition: pg_checksums.c:61
char * datadir_target
Definition: pg_rewind.c:53
static int dstfd
Definition: file_ops.c:29
void open_target_file(const char *path, bool trunc)
Definition: file_ops.c:42
int pg_file_create_mode
Definition: file_perm.c:19
void write_target_range(char *buf, off_t begin, size_t size)
Definition: file_ops.c:83
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define write(a, b, c)
Definition: win32.h:14
bool dry_run
Definition: pg_rewind.c:59
void remove_target_file(const char *path, bool missing_ok)
Definition: file_ops.c:172
#define pg_fatal(...)
Definition: pg_rewind.h:43
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1216
void truncate_target_file(const char *path, off_t newsize)
Definition: file_ops.c:191
file_type_t type
Definition: filemap.h:45
static void create_target_symlink(const char *path, const char *link)
Definition: file_ops.c:242
#define MAXPGPATH
file_action_t action
Definition: filemap.h:47
char * link_target
Definition: filemap.h:57
static char * buf
Definition: pg_test_fsync.c:67
#define symlink(oldpath, newpath)
Definition: win32_port.h:221
static void remove_target_symlink(const char *path)
Definition: file_ops.c:256
char * datadir
static void progress_report(int tablespacenum, const char *filename, bool force)
static char dstpath[MAXPGPATH]
Definition: file_ops.c:30
#define stat(a, b)
Definition: win32_port.h:255
static void remove_target_dir(const char *path)
Definition: file_ops.c:228
int pg_dir_create_mode
Definition: file_perm.c:18
static void create_target_dir(const char *path)
Definition: file_ops.c:214
void remove_target(file_entry_t *entry)
Definition: file_ops.c:125
#define Assert(condition)
Definition: c.h:733
size_t Size
Definition: c.h:467
char * path
Definition: filemap.h:44
void close_target_file(void)
Definition: file_ops.c:70
Definition: filemap.h:42
void create_target(file_entry_t *entry)
Definition: file_ops.c:146
#define mkdir(a, b)
Definition: win32_port.h:58
uint64 fetch_done
Definition: pg_rewind.c:68
#define close(a)
Definition: win32.h:12
#define snprintf
Definition: port.h:192
#define read(a, b, c)
Definition: win32.h:13
char * slurpFile(const char *datadir, const char *path, size_t *filesize)
Definition: file_ops.c:284
#define ftruncate(a, b)
Definition: win32_port.h:60