Commit 558730ac authored by Tom Lane's avatar Tom Lane

Clean up CREATE DATABASE processing to make it more robust and get rid

of special case for Windows port.  Put a PG_TRY around most of createdb()
to ensure that we remove copied subdirectories on failure, even if the
failure happens while creating the pg_database row.  (I think this explains
Oliver Siegmar's recent report.)  Having done that, there's no need for
the fragile assumption that copydir() mustn't ereport(ERROR), so simplify
its API.  Eliminate the old code that used system("cp ...") to copy
subdirectories, in favor of using copydir() on all platforms.  This not
only should allow much better error reporting, but allows us to fsync
the created files before trusting that the copy has succeeded.
parent 0001e98d
...@@ -14915,14 +14915,6 @@ fi ...@@ -14915,14 +14915,6 @@ fi
# Win32 support # Win32 support
if test "$PORTNAME" = "win32"; then if test "$PORTNAME" = "win32"; then
case $LIBOBJS in
"copydir.$ac_objext" | \
*" copydir.$ac_objext" | \
"copydir.$ac_objext "* | \
*" copydir.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS copydir.$ac_objext" ;;
esac
case $LIBOBJS in case $LIBOBJS in
"gettimeofday.$ac_objext" | \ "gettimeofday.$ac_objext" | \
*" gettimeofday.$ac_objext" | \ *" gettimeofday.$ac_objext" | \
......
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
dnl $PostgreSQL: pgsql/configure.in,v 1.417 2005/07/06 21:04:13 momjian Exp $ dnl $PostgreSQL: pgsql/configure.in,v 1.418 2005/08/02 19:02:30 tgl Exp $
dnl dnl
dnl Developers, please strive to achieve this order: dnl Developers, please strive to achieve this order:
dnl dnl
...@@ -913,7 +913,6 @@ fi ...@@ -913,7 +913,6 @@ fi
# Win32 support # Win32 support
if test "$PORTNAME" = "win32"; then if test "$PORTNAME" = "win32"; then
AC_LIBOBJ(copydir)
AC_LIBOBJ(gettimeofday) AC_LIBOBJ(gettimeofday)
AC_LIBOBJ(kill) AC_LIBOBJ(kill)
AC_LIBOBJ(open) AC_LIBOBJ(open)
......
# -*-makefile-*- # -*-makefile-*-
# $PostgreSQL: pgsql/src/Makefile.global.in,v 1.218 2005/07/28 03:15:52 tgl Exp $ # $PostgreSQL: pgsql/src/Makefile.global.in,v 1.219 2005/08/02 19:02:31 tgl Exp $
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# All PostgreSQL makefiles include this file and use the variables it sets, # All PostgreSQL makefiles include this file and use the variables it sets,
...@@ -388,11 +388,10 @@ endif ...@@ -388,11 +388,10 @@ endif
########################################################################## ##########################################################################
# #
# substitute implementations of C library routines # substitute implementations of C library routines (see src/port/)
LIBOBJS = @LIBOBJS@ dirmod.o exec.o noblock.o path.o pipe.o pgsleep.o pgstrcasecmp.o sprompt.o thread.o LIBOBJS = @LIBOBJS@ copydir.o dirmod.o exec.o noblock.o path.o pipe.o pgsleep.o pgstrcasecmp.o sprompt.o thread.o
ifneq (,$(LIBOBJS))
LIBS := -lpgport $(LIBS) LIBS := -lpgport $(LIBS)
# add location of libpgport.a to LDFLAGS # add location of libpgport.a to LDFLAGS
ifdef PGXS ifdef PGXS
...@@ -400,7 +399,6 @@ override LDFLAGS := -L$(libdir) $(LDFLAGS) ...@@ -400,7 +399,6 @@ override LDFLAGS := -L$(libdir) $(LDFLAGS)
else else
override LDFLAGS := -L$(top_builddir)/src/port $(LDFLAGS) override LDFLAGS := -L$(top_builddir)/src/port $(LDFLAGS)
endif endif
endif
# to make ws2_32.lib the last library, and always link with shfolder, # to make ws2_32.lib the last library, and always link with shfolder,
# so SHGetFolderName isn't picked up from shell32.dll # so SHGetFolderName isn't picked up from shell32.dll
......
This diff is collapsed.
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/port.h,v 1.79 2005/07/06 21:40:09 momjian Exp $ * $PostgreSQL: pgsql/src/include/port.h,v 1.80 2005/08/02 19:02:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -206,6 +206,8 @@ extern int pgsymlink(const char *oldpath, const char *newpath); ...@@ -206,6 +206,8 @@ extern int pgsymlink(const char *oldpath, const char *newpath);
#endif /* defined(WIN32) || defined(__CYGWIN__) */ #endif /* defined(WIN32) || defined(__CYGWIN__) */
extern void copydir(char *fromdir, char *todir, bool recurse);
extern bool rmtree(char *path, bool rmtopdir); extern bool rmtree(char *path, bool rmtopdir);
#if defined(WIN32) && !defined(__CYGWIN__) #if defined(WIN32) && !defined(__CYGWIN__)
...@@ -223,8 +225,6 @@ extern int win32_open(const char *, int,...); ...@@ -223,8 +225,6 @@ extern int win32_open(const char *, int,...);
#define pclose(a) _pclose(a) #define pclose(a) _pclose(a)
#endif #endif
extern int copydir(char *fromdir, char *todir);
/* Missing rand functions */ /* Missing rand functions */
extern long lrand48(void); extern long lrand48(void);
extern void srand48(long seed); extern void srand48(long seed);
......
...@@ -11,84 +11,140 @@ ...@@ -11,84 +11,140 @@
* as a service. * as a service.
* *
* IDENTIFICATION * 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 "postgres.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include "storage/fd.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) * copydir: copy a directory
*
* Return 0 on success, nonzero on failure.
* *
* NB: do not elog(ERROR) on failure. Return to caller so it can try to * If recurse is false, subdirectories are ignored. Anything that's not
* clean up. * a directory or a regular file is ignored.
*/ */
int void
copydir(char *fromdir, char *todir) copydir(char *fromdir, char *todir, bool recurse)
{ {
DIR *xldir; DIR *xldir;
struct dirent *xlde; struct dirent *xlde;
char fromfl[MAXPGPATH]; char fromfile[MAXPGPATH];
char tofl[MAXPGPATH]; char tofile[MAXPGPATH];
if (mkdir(todir) != 0) if (mkdir(todir, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
{ ereport(ERROR,
ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not create directory \"%s\": %m", todir))); errmsg("could not create directory \"%s\": %m", todir)));
return -1;
}
xldir = AllocateDir(fromdir); xldir = AllocateDir(fromdir);
if (xldir == NULL) if (xldir == NULL)
{ ereport(ERROR,
ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m", fromdir))); 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; FreeDir(xldir);
while ((xlde = readdir(xldir)) != NULL) }
/*
* 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); nbytes = read(srcfd, buffer, sizeof(buffer));
snprintf(tofl, MAXPGPATH, "%s/%s", todir, xlde->d_name); if (nbytes < 0)
if (CopyFile(fromfl, tofl, TRUE) < 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(), (errcode_for_file_access(),
errmsg("could not copy file \"%s\": %m", fromfl))); errmsg("could not write to file \"%s\": %m", tofile)));
FreeDir(xldir);
return -1;
} }
errno = 0;
} }
#ifdef WIN32
/* /*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but * Be paranoid here to ensure we catch problems.
* not in released version
*/ */
if (GetLastError() == ERROR_NO_MORE_FILES) if (pg_fsync(dstfd) != 0)
errno = 0; ereport(ERROR,
#endif
if (errno)
{
ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m", fromdir))); errmsg("could not fsync file \"%s\": %m", tofile)));
FreeDir(xldir);
return -1;
}
FreeDir(xldir); if (close(dstfd))
return 0; ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not close file \"%s\": %m", tofile)));
close(srcfd);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment