1
/*-------------------------------------------------------------------------
6
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
9
* While "xcopy /e /i /q" works fine for copying directories, on Windows XP
10
* it requires a Window handle which prevents it from working when invoked
14
* src/backend/storage/file/copydir.c
16
*-------------------------------------------------------------------------
25
#include "storage/copydir.h"
26
#include "storage/fd.h"
27
#include "miscadmin.h"
30
* On Windows, call non-macro versions of palloc; we can't reference
31
* CurrentMemoryContext in this file because of PGDLLIMPORT conflict.
33
#if defined(WIN32) || defined(__CYGWIN__)
36
#define palloc(sz) pgport_palloc(sz)
37
#define pstrdup(str) pgport_pstrdup(str)
41
static void fsync_fname(char *fname, bool isdir);
45
* copydir: copy a directory
47
* If recurse is false, subdirectories are ignored. Anything that's not
48
* a directory or a regular file is ignored.
51
copydir(char *fromdir, char *todir, bool recurse)
55
char fromfile[MAXPGPATH];
56
char tofile[MAXPGPATH];
58
if (mkdir(todir, S_IRWXU) != 0)
60
(errcode_for_file_access(),
61
errmsg("could not create directory \"%s\": %m", todir)));
63
xldir = AllocateDir(fromdir);
66
(errcode_for_file_access(),
67
errmsg("could not open directory \"%s\": %m", fromdir)));
69
while ((xlde = ReadDir(xldir, fromdir)) != NULL)
73
/* If we got a cancel signal during the copy of the directory, quit */
74
CHECK_FOR_INTERRUPTS();
76
if (strcmp(xlde->d_name, ".") == 0 ||
77
strcmp(xlde->d_name, "..") == 0)
80
snprintf(fromfile, MAXPGPATH, "%s/%s", fromdir, xlde->d_name);
81
snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);
83
if (lstat(fromfile, &fst) < 0)
85
(errcode_for_file_access(),
86
errmsg("could not stat file \"%s\": %m", fromfile)));
88
if (S_ISDIR(fst.st_mode))
90
/* recurse to handle subdirectories */
92
copydir(fromfile, tofile, true);
94
else if (S_ISREG(fst.st_mode))
95
copy_file(fromfile, tofile);
100
* Be paranoid here and fsync all files to ensure the copy is really done.
102
xldir = AllocateDir(todir);
105
(errcode_for_file_access(),
106
errmsg("could not open directory \"%s\": %m", todir)));
108
while ((xlde = ReadDir(xldir, todir)) != NULL)
112
if (strcmp(xlde->d_name, ".") == 0 ||
113
strcmp(xlde->d_name, "..") == 0)
116
snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);
119
* We don't need to sync subdirectories here since the recursive
120
* copydir will do it before it returns
122
if (lstat(tofile, &fst) < 0)
124
(errcode_for_file_access(),
125
errmsg("could not stat file \"%s\": %m", tofile)));
127
if (S_ISREG(fst.st_mode))
128
fsync_fname(tofile, false);
133
* It's important to fsync the destination directory itself as individual
134
* file fsyncs don't guarantee that the directory entry for the file is
135
* synced. Recent versions of ext4 have made the window much wider but
136
* it's been true for ext3 and other filesystems in the past.
138
fsync_fname(todir, true);
145
copy_file(char *fromfile, char *tofile)
153
/* Use palloc to ensure we get a maxaligned buffer */
154
#define COPY_BUF_SIZE (8 * BLCKSZ)
156
buffer = palloc(COPY_BUF_SIZE);
161
srcfd = BasicOpenFile(fromfile, O_RDONLY | PG_BINARY, 0);
164
(errcode_for_file_access(),
165
errmsg("could not open file \"%s\": %m", fromfile)));
167
dstfd = BasicOpenFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
171
(errcode_for_file_access(),
172
errmsg("could not create file \"%s\": %m", tofile)));
175
* Do the data copying.
177
for (offset = 0;; offset += nbytes)
179
/* If we got a cancel signal during the copy of the file, quit */
180
CHECK_FOR_INTERRUPTS();
182
nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
185
(errcode_for_file_access(),
186
errmsg("could not read file \"%s\": %m", fromfile)));
190
if ((int) write(dstfd, buffer, nbytes) != nbytes)
192
/* if write didn't set errno, assume problem is no disk space */
196
(errcode_for_file_access(),
197
errmsg("could not write to file \"%s\": %m", tofile)));
201
* We fsync the files later but first flush them to avoid spamming the
202
* cache and hopefully get the kernel to start writing them out before
205
pg_flush_data(dstfd, offset, nbytes);
210
(errcode_for_file_access(),
211
errmsg("could not close file \"%s\": %m", tofile)));
222
* Try to fsync directories but ignore errors that indicate the OS
223
* just doesn't allow/require fsyncing directories.
226
fsync_fname(char *fname, bool isdir)
232
* Some OSs require directories to be opened read-only whereas other
233
* systems don't allow us to fsync files opened read-only; so we need both
237
fd = BasicOpenFile(fname,
241
fd = BasicOpenFile(fname,
242
O_RDONLY | PG_BINARY,
246
* Some OSs don't allow us to open directories at all (Windows returns
249
if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES))
254
(errcode_for_file_access(),
255
errmsg("could not open file \"%s\": %m", fname)));
257
returncode = pg_fsync(fd);
259
/* Some OSs don't allow us to fsync directories at all */
260
if (returncode != 0 && isdir && errno == EBADF)
268
(errcode_for_file_access(),
269
errmsg("could not fsync file \"%s\": %m", fname)));