00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "postgres.h"
00020
00021 #include <fcntl.h>
00022 #include <unistd.h>
00023 #include <sys/stat.h>
00024
00025 #include "storage/copydir.h"
00026 #include "storage/fd.h"
00027 #include "miscadmin.h"
00028
00029
00030 static void fsync_fname(char *fname, bool isdir);
00031
00032
00033
00034
00035
00036
00037
00038
00039 void
00040 copydir(char *fromdir, char *todir, bool recurse)
00041 {
00042 DIR *xldir;
00043 struct dirent *xlde;
00044 char fromfile[MAXPGPATH];
00045 char tofile[MAXPGPATH];
00046
00047 if (mkdir(todir, S_IRWXU) != 0)
00048 ereport(ERROR,
00049 (errcode_for_file_access(),
00050 errmsg("could not create directory \"%s\": %m", todir)));
00051
00052 xldir = AllocateDir(fromdir);
00053 if (xldir == NULL)
00054 ereport(ERROR,
00055 (errcode_for_file_access(),
00056 errmsg("could not open directory \"%s\": %m", fromdir)));
00057
00058 while ((xlde = ReadDir(xldir, fromdir)) != NULL)
00059 {
00060 struct stat fst;
00061
00062
00063 CHECK_FOR_INTERRUPTS();
00064
00065 if (strcmp(xlde->d_name, ".") == 0 ||
00066 strcmp(xlde->d_name, "..") == 0)
00067 continue;
00068
00069 snprintf(fromfile, MAXPGPATH, "%s/%s", fromdir, xlde->d_name);
00070 snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);
00071
00072 if (lstat(fromfile, &fst) < 0)
00073 ereport(ERROR,
00074 (errcode_for_file_access(),
00075 errmsg("could not stat file \"%s\": %m", fromfile)));
00076
00077 if (S_ISDIR(fst.st_mode))
00078 {
00079
00080 if (recurse)
00081 copydir(fromfile, tofile, true);
00082 }
00083 else if (S_ISREG(fst.st_mode))
00084 copy_file(fromfile, tofile);
00085 }
00086 FreeDir(xldir);
00087
00088
00089
00090
00091
00092 if (!enableFsync)
00093 return;
00094
00095 xldir = AllocateDir(todir);
00096 if (xldir == NULL)
00097 ereport(ERROR,
00098 (errcode_for_file_access(),
00099 errmsg("could not open directory \"%s\": %m", todir)));
00100
00101 while ((xlde = ReadDir(xldir, todir)) != NULL)
00102 {
00103 struct stat fst;
00104
00105 if (strcmp(xlde->d_name, ".") == 0 ||
00106 strcmp(xlde->d_name, "..") == 0)
00107 continue;
00108
00109 snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);
00110
00111
00112
00113
00114
00115 if (lstat(tofile, &fst) < 0)
00116 ereport(ERROR,
00117 (errcode_for_file_access(),
00118 errmsg("could not stat file \"%s\": %m", tofile)));
00119
00120 if (S_ISREG(fst.st_mode))
00121 fsync_fname(tofile, false);
00122 }
00123 FreeDir(xldir);
00124
00125
00126
00127
00128
00129
00130
00131 fsync_fname(todir, true);
00132 }
00133
00134
00135
00136
00137 void
00138 copy_file(char *fromfile, char *tofile)
00139 {
00140 char *buffer;
00141 int srcfd;
00142 int dstfd;
00143 int nbytes;
00144 off_t offset;
00145
00146
00147 #define COPY_BUF_SIZE (8 * BLCKSZ)
00148
00149 buffer = palloc(COPY_BUF_SIZE);
00150
00151
00152
00153
00154 srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY, 0);
00155 if (srcfd < 0)
00156 ereport(ERROR,
00157 (errcode_for_file_access(),
00158 errmsg("could not open file \"%s\": %m", fromfile)));
00159
00160 dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
00161 S_IRUSR | S_IWUSR);
00162 if (dstfd < 0)
00163 ereport(ERROR,
00164 (errcode_for_file_access(),
00165 errmsg("could not create file \"%s\": %m", tofile)));
00166
00167
00168
00169
00170 for (offset = 0;; offset += nbytes)
00171 {
00172
00173 CHECK_FOR_INTERRUPTS();
00174
00175 nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
00176 if (nbytes < 0)
00177 ereport(ERROR,
00178 (errcode_for_file_access(),
00179 errmsg("could not read file \"%s\": %m", fromfile)));
00180 if (nbytes == 0)
00181 break;
00182 errno = 0;
00183 if ((int) write(dstfd, buffer, nbytes) != nbytes)
00184 {
00185
00186 if (errno == 0)
00187 errno = ENOSPC;
00188 ereport(ERROR,
00189 (errcode_for_file_access(),
00190 errmsg("could not write to file \"%s\": %m", tofile)));
00191 }
00192
00193
00194
00195
00196
00197
00198 (void) pg_flush_data(dstfd, offset, nbytes);
00199 }
00200
00201 if (CloseTransientFile(dstfd))
00202 ereport(ERROR,
00203 (errcode_for_file_access(),
00204 errmsg("could not close file \"%s\": %m", tofile)));
00205
00206 CloseTransientFile(srcfd);
00207
00208 pfree(buffer);
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218 static void
00219 fsync_fname(char *fname, bool isdir)
00220 {
00221 int fd;
00222 int returncode;
00223
00224
00225
00226
00227
00228
00229 if (!isdir)
00230 fd = OpenTransientFile(fname,
00231 O_RDWR | PG_BINARY,
00232 S_IRUSR | S_IWUSR);
00233 else
00234 fd = OpenTransientFile(fname,
00235 O_RDONLY | PG_BINARY,
00236 S_IRUSR | S_IWUSR);
00237
00238
00239
00240
00241
00242 if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES))
00243 return;
00244
00245 else if (fd < 0)
00246 ereport(ERROR,
00247 (errcode_for_file_access(),
00248 errmsg("could not open file \"%s\": %m", fname)));
00249
00250 returncode = pg_fsync(fd);
00251
00252
00253 if (returncode != 0 && isdir && errno == EBADF)
00254 {
00255 CloseTransientFile(fd);
00256 return;
00257 }
00258
00259 if (returncode != 0)
00260 ereport(ERROR,
00261 (errcode_for_file_access(),
00262 errmsg("could not fsync file \"%s\": %m", fname)));
00263
00264 CloseTransientFile(fd);
00265 }