aboutsummaryrefslogtreecommitdiff
path: root/src/port/copydir.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/port/copydir.c')
-rw-r--r--src/port/copydir.c146
1 files changed, 101 insertions, 45 deletions
diff --git a/src/port/copydir.c b/src/port/copydir.c
index 6062da96a84..a9339e79f90 100644
--- a/src/port/copydir.c
+++ b/src/port/copydir.c
@@ -11,84 +11,140 @@
* as a service.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/port/copydir.c,v 1.11 2005/03/24 02:11:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/port/copydir.c,v 1.12 2005/08/02 19:02:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
#include "storage/fd.h"
-#undef mkdir /* no reason to use that macro because we
- * ignore the 2nd arg */
+
+static void copy_file(char *fromfile, char *tofile);
/*
- * copydir: copy a directory (we only need to go one level deep)
- *
- * Return 0 on success, nonzero on failure.
+ * copydir: copy a directory
*
- * NB: do not elog(ERROR) on failure. Return to caller so it can try to
- * clean up.
+ * If recurse is false, subdirectories are ignored. Anything that's not
+ * a directory or a regular file is ignored.
*/
-int
-copydir(char *fromdir, char *todir)
+void
+copydir(char *fromdir, char *todir, bool recurse)
{
DIR *xldir;
struct dirent *xlde;
- char fromfl[MAXPGPATH];
- char tofl[MAXPGPATH];
+ char fromfile[MAXPGPATH];
+ char tofile[MAXPGPATH];
- if (mkdir(todir) != 0)
- {
- ereport(WARNING,
+ if (mkdir(todir, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
+ ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create directory \"%s\": %m", todir)));
- return -1;
- }
+
xldir = AllocateDir(fromdir);
if (xldir == NULL)
- {
- ereport(WARNING,
+ ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m", fromdir)));
- return -1;
+
+ while ((xlde = ReadDir(xldir, fromdir)) != NULL)
+ {
+ struct stat fst;
+
+ if (strcmp(xlde->d_name, ".") == 0 ||
+ strcmp(xlde->d_name, "..") == 0)
+ continue;
+
+ snprintf(fromfile, MAXPGPATH, "%s/%s", fromdir, xlde->d_name);
+ snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);
+
+ if (stat(fromfile, &fst) < 0)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not stat \"%s\": %m", fromfile)));
+
+ if (fst.st_mode & S_IFDIR)
+ {
+ /* recurse to handle subdirectories */
+ if (recurse)
+ copydir(fromfile, tofile, true);
+ }
+ else if (fst.st_mode & S_IFREG)
+ copy_file(fromfile, tofile);
}
- errno = 0;
- while ((xlde = readdir(xldir)) != NULL)
+ FreeDir(xldir);
+}
+
+/*
+ * copy one file
+ */
+static void
+copy_file(char *fromfile, char *tofile)
+{
+ char buffer[8 * BLCKSZ];
+ int srcfd;
+ int dstfd;
+ int nbytes;
+
+ /*
+ * Open the files
+ */
+ srcfd = BasicOpenFile(fromfile, O_RDONLY | PG_BINARY, 0);
+ if (srcfd < 0)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not open file \"%s\": %m", fromfile)));
+
+ dstfd = BasicOpenFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
+ S_IRUSR | S_IWUSR);
+ if (dstfd < 0)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not create file \"%s\": %m", tofile)));
+
+ /*
+ * Do the data copying.
+ */
+ for (;;)
{
- snprintf(fromfl, MAXPGPATH, "%s/%s", fromdir, xlde->d_name);
- snprintf(tofl, MAXPGPATH, "%s/%s", todir, xlde->d_name);
- if (CopyFile(fromfl, tofl, TRUE) < 0)
+ nbytes = read(srcfd, buffer, sizeof(buffer));
+ if (nbytes < 0)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not read file \"%s\": %m", fromfile)));
+ if (nbytes == 0)
+ break;
+ errno = 0;
+ if ((int) write(dstfd, buffer, nbytes) != nbytes)
{
- ereport(WARNING,
+ /* if write didn't set errno, assume problem is no disk space */
+ if (errno == 0)
+ errno = ENOSPC;
+ ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not copy file \"%s\": %m", fromfl)));
- FreeDir(xldir);
- return -1;
+ errmsg("could not write to file \"%s\": %m", tofile)));
}
- errno = 0;
}
-#ifdef WIN32
/*
- * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
- * not in released version
+ * Be paranoid here to ensure we catch problems.
*/
- if (GetLastError() == ERROR_NO_MORE_FILES)
- errno = 0;
-#endif
- if (errno)
- {
- ereport(WARNING,
+ if (pg_fsync(dstfd) != 0)
+ ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not read directory \"%s\": %m", fromdir)));
- FreeDir(xldir);
- return -1;
- }
+ errmsg("could not fsync file \"%s\": %m", tofile)));
- FreeDir(xldir);
- return 0;
+ if (close(dstfd))
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not close file \"%s\": %m", tofile)));
+
+ close(srcfd);
}