4 * file system operations
6 * Copyright (c) 2010-2015, PostgreSQL Global Development Group
7 * contrib/pg_upgrade/file.c
10 #include "postgres_fe.h"
12 #include "pg_upgrade.h"
19 static int copy_file(const char *fromfile, const char *tofile, bool force);
21 static int win32_pghardlink(const char *src, const char *dst);
28 * Copies a relation file from src to dst. If pageConverter is non-NULL, this function
29 * uses that pageConverter to do a page-by-page conversion.
32 copyAndUpdateFile(pageCnvCtx *pageConverter,
33 const char *src, const char *dst, bool force)
35 if (pageConverter == NULL)
37 if (pg_copy_file(src, dst, force) == -1)
38 return getErrorText(errno);
45 * We have a pageConverter object - that implies that the
46 * PageLayoutVersion differs between the two clusters so we have to
47 * perform a page-by-page conversion.
49 * If the pageConverter can convert the entire file at once, invoke
50 * that plugin function, otherwise, read each page in the relation
51 * file and call the convertPage plugin function.
54 #ifdef PAGE_CONVERSION
55 if (pageConverter->convertFile)
56 return pageConverter->convertFile(pageConverter->pluginData,
65 const char *msg = NULL;
67 if ((src_fd = open(src, O_RDONLY, 0)) < 0)
68 return "could not open source file";
70 if ((dstfd = open(dst, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
73 return "could not create destination file";
76 while ((bytesRead = read(src_fd, buf, BLCKSZ)) == BLCKSZ)
78 #ifdef PAGE_CONVERSION
79 if ((msg = pageConverter->convertPage(pageConverter->pluginData, buf, buf)) != NULL)
82 if (write(dstfd, buf, BLCKSZ) != BLCKSZ)
84 msg = "could not write new page to destination";
94 else if (bytesRead != 0)
95 return "found partial page in source file";
104 * linkAndUpdateFile()
106 * Creates a hard link between the given relation files. We use
107 * this function to perform a true in-place update. If the on-disk
108 * format of the new cluster is bit-for-bit compatible with the on-disk
109 * format of the old cluster, we can simply link each relation
110 * instead of copying the data from the old cluster to the new cluster.
113 linkAndUpdateFile(pageCnvCtx *pageConverter,
114 const char *src, const char *dst)
116 if (pageConverter != NULL)
117 return "Cannot in-place update this cluster, page-by-page conversion is required";
119 if (pg_link_file(src, dst) == -1)
120 return getErrorText(errno);
128 copy_file(const char *srcfile, const char *dstfile, bool force)
130 #define COPY_BUF_SIZE (50 * BLCKSZ)
138 if ((srcfile == NULL) || (dstfile == NULL))
144 if ((src_fd = open(srcfile, O_RDONLY, 0)) < 0)
147 if ((dest_fd = open(dstfile, O_RDWR | O_CREAT | (force ? 0 : O_EXCL), S_IRUSR | S_IWUSR)) < 0)
158 buffer = (char *) pg_malloc(COPY_BUF_SIZE);
160 /* perform data copying i.e read src source, write to destination */
163 ssize_t nbytes = read(src_fd, buffer, COPY_BUF_SIZE);
177 if (write(dest_fd, buffer, nbytes) != nbytes)
179 /* if write didn't set errno, assume problem is no disk space */
205 check_hard_link(void)
207 char existing_file[MAXPGPATH];
208 char new_link_file[MAXPGPATH];
210 snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata);
211 snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.linktest", new_cluster.pgdata);
212 unlink(new_link_file); /* might fail */
214 if (pg_link_file(existing_file, new_link_file) == -1)
216 pg_fatal("Could not create hard link between old and new data directories: %s\n"
217 "In link mode the old and new data directories must be on the same file system volume.\n",
218 getErrorText(errno));
220 unlink(new_link_file);
225 win32_pghardlink(const char *src, const char *dst)
228 * CreateHardLinkA returns zero for failure
229 * http://msdn.microsoft.com/en-us/library/aa363860(VS.85).aspx
231 if (CreateHardLinkA(dst, src, NULL) == 0)
239 /* fopen() file with no group/other permissions */
241 fopen_priv(const char *path, const char *mode)
243 mode_t old_umask = umask(S_IRWXG | S_IRWXO);
246 fp = fopen(path, mode);