diff options
author | Robert Haas <rhaas@postgresql.org> | 2010-07-02 17:03:38 +0000 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2010-07-02 17:03:38 +0000 |
commit | d7f51b2c49d24462cbfa3f1618a7b51e4c4ff00c (patch) | |
tree | 4d055905d1861798818b2fd0b3160ca8e03dafba /src/backend/storage | |
parent | 5976be32d2d80e0e4f5717a8c890bbcdf6580da1 (diff) | |
download | postgresql-d7f51b2c49d24462cbfa3f1618a7b51e4c4ff00c.tar.gz postgresql-d7f51b2c49d24462cbfa3f1618a7b51e4c4ff00c.zip |
Move copydir.c from src/port to src/backend/storage/file
The previous commit to make copydir() interruptible prevented
postgres.exe from linking on MinGW and Cygwin, because on those
platforms libpgport_srv.a can't freely reference symbols defined
by the backend. Since that code is already backend-specific anyway,
just move the whole file into the backend rather than adding further
kludges to deal with the symbols needed by CHECK_FOR_INTERRUPTS().
This probably needs some further cleanup, but this commit just moves
the file as-is, which should hopefully be enough to turn the
buildfarm green again.
Diffstat (limited to 'src/backend/storage')
-rw-r--r-- | src/backend/storage/file/Makefile | 4 | ||||
-rw-r--r-- | src/backend/storage/file/copydir.c | 175 |
2 files changed, 177 insertions, 2 deletions
diff --git a/src/backend/storage/file/Makefile b/src/backend/storage/file/Makefile index c891f704eb7..c0dae9cc435 100644 --- a/src/backend/storage/file/Makefile +++ b/src/backend/storage/file/Makefile @@ -4,7 +4,7 @@ # Makefile for storage/file # # IDENTIFICATION -# $PostgreSQL: pgsql/src/backend/storage/file/Makefile,v 1.13 2008/02/19 10:30:08 petere Exp $ +# $PostgreSQL: pgsql/src/backend/storage/file/Makefile,v 1.13.2.1 2010/07/02 17:03:38 rhaas Exp $ # #------------------------------------------------------------------------- @@ -12,6 +12,6 @@ subdir = src/backend/storage/file top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -OBJS = fd.o buffile.o +OBJS = fd.o buffile.o copydir.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c new file mode 100644 index 00000000000..3527db4e2ae --- /dev/null +++ b/src/backend/storage/file/copydir.c @@ -0,0 +1,175 @@ +/*------------------------------------------------------------------------- + * + * copydir.c + * copies a directory + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * While "xcopy /e /i /q" works fine for copying directories, on Windows XP + * it requires a Window handle which prevents it from working when invoked + * as a service. + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/storage/file/copydir.c,v 1.1.2.1 2010/07/02 17:03:38 rhaas Exp $ + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> + +#include "storage/fd.h" +#include "miscadmin.h" + +/* + * On Windows, call non-macro versions of palloc; we can't reference + * CurrentMemoryContext in this file because of PGDLLIMPORT conflict. + */ +#if defined(WIN32) || defined(__CYGWIN__) +#undef palloc +#undef pstrdup +#define palloc(sz) pgport_palloc(sz) +#define pstrdup(str) pgport_pstrdup(str) +#endif + + +static void copy_file(char *fromfile, char *tofile); + + +/* + * copydir: copy a directory + * + * If recurse is false, subdirectories are ignored. Anything that's not + * a directory or a regular file is ignored. + */ +void +copydir(char *fromdir, char *todir, bool recurse) +{ + DIR *xldir; + struct dirent *xlde; + char fromfile[MAXPGPATH]; + char tofile[MAXPGPATH]; + + if (mkdir(todir, S_IRUSR | S_IWUSR | S_IXUSR) != 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not create directory \"%s\": %m", todir))); + + xldir = AllocateDir(fromdir); + if (xldir == NULL) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not open directory \"%s\": %m", fromdir))); + + while ((xlde = ReadDir(xldir, fromdir)) != NULL) + { + struct stat fst; + + /* If we got a cancel signal during the copy of the directory, quit */ + CHECK_FOR_INTERRUPTS(); + + 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 (lstat(fromfile, &fst) < 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", fromfile))); + + if (S_ISDIR(fst.st_mode)) + { + /* recurse to handle subdirectories */ + if (recurse) + copydir(fromfile, tofile, true); + } + else if (S_ISREG(fst.st_mode)) + copy_file(fromfile, tofile); + } + + FreeDir(xldir); +} + +/* + * copy one file + */ +static void +copy_file(char *fromfile, char *tofile) +{ + char *buffer; + int srcfd; + int dstfd; + int nbytes; + + /* Use palloc to ensure we get a maxaligned buffer */ +#define COPY_BUF_SIZE (8 * BLCKSZ) + + buffer = palloc(COPY_BUF_SIZE); + + /* + * 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 (;;) + { + /* If we got a cancel signal during the copy of the file, quit */ + CHECK_FOR_INTERRUPTS(); + + nbytes = read(srcfd, buffer, COPY_BUF_SIZE); + 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) + { + /* 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 write to file \"%s\": %m", tofile))); + } + } + + /* + * Be paranoid here to ensure we catch problems. + */ + if (pg_fsync(dstfd) != 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not fsync file \"%s\": %m", tofile))); + + if (close(dstfd)) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not close file \"%s\": %m", tofile))); + + close(srcfd); + + pfree(buffer); +} |