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