提交 67119992 编写于 作者: T Tom Lane

Move a couple of initdb's subroutines into src/port/.

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.
上级 04f4e10c
......@@ -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
......@@ -801,59 +694,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)
*/
......@@ -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,
......
......@@ -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 */
......@@ -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
......
/*-------------------------------------------------------------------------
*
* 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;
}
/*
* 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;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册