OSDN Git Service

Move a couple of initdb's subroutines into src/port/.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 11 Dec 2010 00:42:44 +0000 (19:42 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 11 Dec 2010 00:42:44 +0000 (19:42 -0500)
mkdir_p and check_data_dir will be useful in CREATE TABLESPACE, since we
have agreed that that command should handle subdirectory creation just like
initdb creates the PGDATA directory.  Push them into src/port/ so that they
are available to both initdb and the backend.  Rename to pg_mkdir_p and
pg_check_dir, just to be on the safe side.  Add FreeBSD's copyright notice
to pgmkdirp.c, since that's where the code came from originally (this
really should have been in initdb.c).  Very marginal code/comment cleanup.

src/bin/initdb/initdb.c
src/include/port.h
src/port/Makefile
src/port/pgcheckdir.c [new file with mode: 0644]
src/port/pgmkdirp.c [new file with mode: 0644]

index 19033ed..040cbdf 100644 (file)
@@ -40,7 +40,6 @@
  *
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
- * Portions taken from FreeBSD.
  *
  * src/bin/initdb/initdb.c
  *
@@ -152,11 +151,9 @@ static char **filter_lines_with_token(char **lines, const char *token);
 static char **readfile(const char *path);
 static void writefile(char *path, char **lines);
 static FILE *popen_check(const char *command, const char *mode);
-static int     mkdir_p(char *path, mode_t omode);
 static void exit_nicely(void);
 static char *get_id(void);
 static char *get_encoding_id(char *encoding_name);
-static int     check_data_dir(char *dir);
 static bool mkdatadir(const char *subdir);
 static void set_input(char **dest, char *filename);
 static void check_input(char *path);
@@ -470,110 +467,6 @@ popen_check(const char *command, const char *mode)
        return cmdfd;
 }
 
-/* source stolen from FreeBSD /src/bin/mkdir/mkdir.c and adapted */
-
-/*
- * this tries to build all the elements of a path to a directory a la mkdir -p
- * we assume the path is in canonical form, i.e. uses / as the separator
- * we also assume it isn't null.
- *
- * note that on failure, the path arg has been modified to show the particular
- * directory level we had problems with.
- */
-static int
-mkdir_p(char *path, mode_t omode)
-{
-       struct stat sb;
-       mode_t          numask,
-                               oumask;
-       int                     first,
-                               last,
-                               retval;
-       char       *p;
-
-       p = path;
-       oumask = 0;
-       retval = 0;
-
-#ifdef WIN32
-       /* skip network and drive specifiers for win32 */
-       if (strlen(p) >= 2)
-       {
-               if (p[0] == '/' && p[1] == '/')
-               {
-                       /* network drive */
-                       p = strstr(p + 2, "/");
-                       if (p == NULL)
-                               return 1;
-               }
-               else if (p[1] == ':' &&
-                                ((p[0] >= 'a' && p[0] <= 'z') ||
-                                 (p[0] >= 'A' && p[0] <= 'Z')))
-               {
-                       /* local drive */
-                       p += 2;
-               }
-       }
-#endif
-
-       if (p[0] == '/')                        /* Skip leading '/'. */
-               ++p;
-       for (first = 1, last = 0; !last; ++p)
-       {
-               if (p[0] == '\0')
-                       last = 1;
-               else if (p[0] != '/')
-                       continue;
-               *p = '\0';
-               if (!last && p[1] == '\0')
-                       last = 1;
-               if (first)
-               {
-                       /*
-                        * POSIX 1003.2: For each dir operand that does not name an
-                        * existing directory, effects equivalent to those caused by the
-                        * following command shall occcur:
-                        *
-                        * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]
-                        * dir
-                        *
-                        * We change the user's umask and then restore it, instead of
-                        * doing chmod's.
-                        */
-                       oumask = umask(0);
-                       numask = oumask & ~(S_IWUSR | S_IXUSR);
-                       (void) umask(numask);
-                       first = 0;
-               }
-               if (last)
-                       (void) umask(oumask);
-
-               /* check for pre-existing directory; ok if it's a parent */
-               if (stat(path, &sb) == 0)
-               {
-                       if (!S_ISDIR(sb.st_mode))
-                       {
-                               if (last)
-                                       errno = EEXIST;
-                               else
-                                       errno = ENOTDIR;
-                               retval = 1;
-                               break;
-                       }
-               }
-               else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
-               {
-                       retval = 1;
-                       break;
-               }
-               if (!last)
-                       *p = '/';
-       }
-       if (!first && !last)
-               (void) umask(oumask);
-       return retval;
-}
-
 /*
  * clean up any files we created on failure
  * if we created the data directory remove it too
@@ -802,59 +695,6 @@ find_matching_ts_config(const char *lc_type)
 
 
 /*
- * make sure the directory either doesn't exist or is empty
- *
- * Returns 0 if nonexistent, 1 if exists and empty, 2 if not empty,
- * or -1 if trouble accessing directory
- */
-static int
-check_data_dir(char *dir)
-{
-       DIR                *chkdir;
-       struct dirent *file;
-       int                     result = 1;
-
-       errno = 0;
-
-       chkdir = opendir(dir);
-
-       if (!chkdir)
-               return (errno == ENOENT) ? 0 : -1;
-
-       while ((file = readdir(chkdir)) != NULL)
-       {
-               if (strcmp(".", file->d_name) == 0 ||
-                       strcmp("..", file->d_name) == 0)
-               {
-                       /* skip this and parent directory */
-                       continue;
-               }
-               else
-               {
-                       result = 2;                     /* not empty */
-                       break;
-               }
-       }
-
-#ifdef WIN32
-
-       /*
-        * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
-        * released version
-        */
-       if (GetLastError() == ERROR_NO_MORE_FILES)
-               errno = 0;
-#endif
-
-       closedir(chkdir);
-
-       if (errno != 0)
-               result = -1;                    /* some kind of I/O error? */
-
-       return result;
-}
-
-/*
  * make the data directory (or one of its subdirectories if subdir is not NULL)
  */
 static bool
@@ -870,7 +710,7 @@ mkdatadir(const char *subdir)
        else
                strcpy(path, pg_data);
 
-       if (mkdir_p(path, S_IRWXU) == 0)
+       if (pg_mkdir_p(path, S_IRWXU) == 0)
                return true;
 
        fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
@@ -2929,7 +2769,7 @@ main(int argc, char *argv[])
        pqsignal(SIGPIPE, SIG_IGN);
 #endif
 
-       switch (check_data_dir(pg_data))
+       switch (pg_check_dir(pg_data))
        {
                case 0:
                        /* PGDATA not there, must create it */
@@ -2995,8 +2835,8 @@ main(int argc, char *argv[])
                        exit_nicely();
                }
 
-               /* check if the specified xlog directory is empty */
-               switch (check_data_dir(xlog_dir))
+               /* check if the specified xlog directory exists/is empty */
+               switch (pg_check_dir(xlog_dir))
                {
                        case 0:
                                /* xlog directory not there, must create it */
@@ -3004,7 +2844,7 @@ main(int argc, char *argv[])
                                           xlog_dir);
                                fflush(stdout);
 
-                               if (mkdir_p(xlog_dir, S_IRWXU) != 0)
+                               if (pg_mkdir_p(xlog_dir, S_IRWXU) != 0)
                                {
                                        fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
                                                        progname, xlog_dir, strerror(errno));
@@ -3015,6 +2855,7 @@ main(int argc, char *argv[])
 
                                made_new_xlogdir = true;
                                break;
+
                        case 1:
                                /* Present but empty, fix permissions and use it */
                                printf(_("fixing permissions on existing directory %s ... "),
@@ -3032,6 +2873,7 @@ main(int argc, char *argv[])
 
                                found_existing_xlogdir = true;
                                break;
+
                        case 2:
                                /* Present and not empty */
                                fprintf(stderr,
index 0cfbed8..0dbc322 100644 (file)
@@ -441,4 +441,10 @@ extern int pg_get_encoding_from_locale(const char *ctype);
 extern char *inet_net_ntop(int af, const void *src, int bits,
                          char *dst, size_t size);
 
+/* port/pgcheckdir.c */
+extern int     pg_check_dir(const char *dir);
+
+/* port/pgmkdirp.c */
+extern int     pg_mkdir_p(char *path, int omode);
+
 #endif   /* PG_PORT_H */
index 711f633..fc65e4b 100644 (file)
@@ -14,8 +14,8 @@
 #      libpgport_srv.a - contains object files without FRONTEND defined,
 #              for use only by the backend binaries
 #
-# LIBOBJS is set by configure (via Makefile.global) to be the list of
-# object files that are conditionally needed as determined by configure's probing.
+# LIBOBJS is set by configure (via Makefile.global) to be the list of object
+# files that are conditionally needed as determined by configure's probing.
 # OBJS adds additional object files that are always compiled.
 #
 # IDENTIFICATION
@@ -30,8 +30,10 @@ include $(top_builddir)/src/Makefile.global
 override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
 LIBS += $(PTHREAD_LIBS)
 
-OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o inet_net_ntop.o noblock.o path.o \
-       pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o
+OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o inet_net_ntop.o noblock.o \
+       path.o pgcheckdir.o pgmkdirp.o pgsleep.o pgstrcasecmp.o \
+       qsort.o qsort_arg.o sprompt.o thread.o
+
 ifneq (,$(filter $(PORTNAME),cygwin win32))
 OBJS += pipe.o
 endif
diff --git a/src/port/pgcheckdir.c b/src/port/pgcheckdir.c
new file mode 100644 (file)
index 0000000..12ec8a6
--- /dev/null
@@ -0,0 +1,73 @@
+/*-------------------------------------------------------------------------
+ *
+ * src/port/pgcheckdir.c
+ *
+ * A simple subroutine to check whether a directory exists and is empty or not.
+ * Useful in both initdb and the backend.
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#include <dirent.h>
+
+
+/*
+ * Test to see if a directory exists and is empty or not.
+ *
+ * Returns:
+ *             0 if nonexistent
+ *             1 if exists and empty
+ *             2 if exists and not empty
+ *             -1 if trouble accessing directory (errno reflects the error)
+ */
+int
+pg_check_dir(const char *dir)
+{
+       int                     result = 1;
+       DIR                *chkdir;
+       struct dirent *file;
+
+       errno = 0;
+
+       chkdir = opendir(dir);
+
+       if (chkdir == NULL)
+               return (errno == ENOENT) ? 0 : -1;
+
+       while ((file = readdir(chkdir)) != NULL)
+       {
+               if (strcmp(".", file->d_name) == 0 ||
+                       strcmp("..", file->d_name) == 0)
+               {
+                       /* skip this and parent directory */
+                       continue;
+               }
+               else
+               {
+                       result = 2;                     /* not empty */
+                       break;
+               }
+       }
+
+#ifdef WIN32
+
+       /*
+        * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
+        * released version
+        */
+       if (GetLastError() == ERROR_NO_MORE_FILES)
+               errno = 0;
+#endif
+
+       closedir(chkdir);
+
+       if (errno != 0)
+               result = -1;                    /* some kind of I/O error? */
+
+       return result;
+}
diff --git a/src/port/pgmkdirp.c b/src/port/pgmkdirp.c
new file mode 100644 (file)
index 0000000..b65db5e
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * This is adapted from FreeBSD's src/bin/mkdir/mkdir.c, which bears
+ * the following copyright notice:
+ *
+ * Copyright (c) 1983, 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "c.h"
+
+#include <sys/stat.h>
+
+
+/*
+ * pg_mkdir_p --- create a directory and, if necessary, parent directories
+ *
+ * This is equivalent to "mkdir -p" except we don't complain if the target
+ * directory already exists.
+ *
+ * We assume the path is in canonical form, i.e., uses / as the separator.
+ *
+ * omode is the file permissions bits for the target directory.  Note that any
+ * parent directories that have to be created get permissions according to the
+ * prevailing umask, but with u+wx forced on to ensure we can create there.
+ * (We declare omode as int, not mode_t, to minimize dependencies for port.h.)
+ *
+ * Returns 0 on success, -1 (with errno set) on failure.
+ *
+ * Note that on failure, the path arg has been modified to show the particular
+ * directory level we had problems with.
+ */
+int
+pg_mkdir_p(char *path, int omode)
+{
+       struct stat sb;
+       mode_t          numask,
+                               oumask;
+       int                     last,
+                               retval;
+       char       *p;
+
+       retval = 0;
+       p = path;
+
+#ifdef WIN32
+       /* skip network and drive specifiers for win32 */
+       if (strlen(p) >= 2)
+       {
+               if (p[0] == '/' && p[1] == '/')
+               {
+                       /* network drive */
+                       p = strstr(p + 2, "/");
+                       if (p == NULL)
+                       {
+                               errno = EINVAL;
+                               return -1;
+                       }
+               }
+               else if (p[1] == ':' &&
+                                ((p[0] >= 'a' && p[0] <= 'z') ||
+                                 (p[0] >= 'A' && p[0] <= 'Z')))
+               {
+                       /* local drive */
+                       p += 2;
+               }
+       }
+#endif
+
+       /*
+        * POSIX 1003.2: For each dir operand that does not name an existing
+        * directory, effects equivalent to those caused by the following command
+        * shall occcur:
+        *
+        * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode] dir
+        *
+        * We change the user's umask and then restore it, instead of doing
+        * chmod's.  Note we assume umask() can't change errno.
+        */
+       oumask = umask(0);
+       numask = oumask & ~(S_IWUSR | S_IXUSR);
+       (void) umask(numask);
+
+       if (p[0] == '/')                        /* Skip leading '/'. */
+               ++p;
+       for (last = 0; !last; ++p)
+       {
+               if (p[0] == '\0')
+                       last = 1;
+               else if (p[0] != '/')
+                       continue;
+               *p = '\0';
+               if (!last && p[1] == '\0')
+                       last = 1;
+
+               if (last)
+                       (void) umask(oumask);
+
+               /* check for pre-existing directory */
+               if (stat(path, &sb) == 0)
+               {
+                       if (!S_ISDIR(sb.st_mode))
+                       {
+                               if (last)
+                                       errno = EEXIST;
+                               else
+                                       errno = ENOTDIR;
+                               retval = -1;
+                               break;
+                       }
+               }
+               else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
+               {
+                       retval = -1;
+                       break;
+               }
+               if (!last)
+                       *p = '/';
+       }
+
+       /* ensure we restored umask */
+       (void) umask(oumask);
+
+       return retval;
+}