Autoconf, libpq and replacement function

Started by Magnus Haganderabout 17 years ago24 messages
#1Magnus Hagander
magnus@hagander.net

Hi!

I want to use the fnmatch() function in libpq, to support wildcard
certificate matching. This function is part of the standard
(http://www.opengroup.org/onlinepubs/000095399/functions/fnmatch.html),
but obviously not implemented on all platforms (naturally, it's missing
on win32, because that makes life harder..)

Anyway. NetBSD has an implementation of this at
http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/gen/fnmatch.c?rev=1.21&content-type=text/x-cvsweb-markup&only_with_tag=MAIN
that we can "steal" if we need.

How do I make this work with the autoconf magic? I see there is an
AC_CHECK_FNMATCH and AC_REPLACE_FNMATCH and so, but I have a feeling I
need to do something different since it's libpq?

(this might be very obvious how to do, but if it is, please excuse my
extreme autoconf-newbiesm)

//Magnus

#2Peter Eisentraut
peter_e@gmx.net
In reply to: Magnus Hagander (#1)
Re: Autoconf, libpq and replacement function

Magnus Hagander wrote:

How do I make this work with the autoconf magic? I see there is an
AC_CHECK_FNMATCH and AC_REPLACE_FNMATCH and so, but I have a feeling I
need to do something different since it's libpq?

AC_*_FNMATCH will figure out whether you need fnmatch(), so something
involving those is necessary.

For libpq, check libpq's Makefile for, say, snprintf, to get an idea
about the "something different".

Altogether, this might not be a trivial case.

#3Magnus Hagander
magnus@hagander.net
In reply to: Peter Eisentraut (#2)
1 attachment(s)
Re: Autoconf, libpq and replacement function

Peter Eisentraut wrote:

Magnus Hagander wrote:

How do I make this work with the autoconf magic? I see there is an
AC_CHECK_FNMATCH and AC_REPLACE_FNMATCH and so, but I have a feeling I
need to do something different since it's libpq?

AC_*_FNMATCH will figure out whether you need fnmatch(), so something
involving those is necessary.

For libpq, check libpq's Makefile for, say, snprintf, to get an idea
about the "something different".

Altogether, this might not be a trivial case.

Hmm. If I did it the right way, it actually didn't seem too hard once I
found a good example. Attached - does that seem reasonable?

(will add msvc code as well)

//Magnus

Attachments:

wildcard_cert.difftext/x-diff; name=wildcard_cert.diffDownload
*** a/configure
--- b/configure
***************
*** 16930,16936 **** LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
  
  
  
! for ac_func in crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul unsetenv
  do
  as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
  { echo "$as_me:$LINENO: checking for $ac_func" >&5
--- 16930,16937 ----
  
  
  
! 
! for ac_func in crypt fnmatch getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul unsetenv
  do
  as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
  { echo "$as_me:$LINENO: checking for $ac_func" >&5
*** a/configure.in
--- b/configure.in
***************
*** 1235,1241 **** fi
  pgac_save_LIBS="$LIBS"
  LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
  
! AC_REPLACE_FUNCS([crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul unsetenv])
  
  LIBS="$pgac_save_LIBS"
  
--- 1235,1241 ----
  pgac_save_LIBS="$LIBS"
  LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
  
! AC_REPLACE_FUNCS([crypt fnmatch getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul unsetenv])
  
  LIBS="$pgac_save_LIBS"
  
*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 143,148 ****
--- 143,151 ----
  /* Define to 1 if you have the `fdatasync' function. */
  #undef HAVE_FDATASYNC
  
+ /* Define to 1 if you have the `fnmatch' function. */
+ #undef HAVE_FNMATCH
+ 
  /* Define to 1 if you have the `fpclass' function. */
  #undef HAVE_FPCLASS
  
*** a/src/include/port.h
--- b/src/include/port.h
***************
*** 393,398 **** extern void unsetenv(const char *name);
--- 393,409 ----
  extern void srandom(unsigned int seed);
  #endif
  
+ #ifdef HAVE_FNMATCH
+ extern int fnmatch(const char *, const char *, int);
+ #define FNM_NOMATCH		1		/* Match failed. */
+ #define FNM_NOSYS		2		/* Function not implemented. */
+ #define FNM_NOESCAPE	0x01	/* Disable backslash escaping. */
+ #define FNM_PATHNAME	0x02	/* Slash must be matched by slash. */
+ #define FNM_PERIOD		0x04	/* Period must be matched by period. */
+ #define FNM_CASEFOLD	0x08	/* Pattern is matched case-insensitive */
+ #define FNM_LEADING_DIR	0x10	/* Ignore /<tail> after Imatch. */
+ #endif
+ 
  /* thread.h */
  extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen);
  
*** a/src/interfaces/libpq/Makefile
--- b/src/interfaces/libpq/Makefile
***************
*** 34,40 **** OBJS=	fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
  	fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
  	libpq-events.o \
  	md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
! 	$(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
  
  ifeq ($(PORTNAME), cygwin)
  override shlib = cyg$(NAME)$(DLSUFFIX)
--- 34,40 ----
  	fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
  	libpq-events.o \
  	md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
! 	$(filter crypt.o fnmatch.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
  
  ifeq ($(PORTNAME), cygwin)
  override shlib = cyg$(NAME)$(DLSUFFIX)
***************
*** 80,86 **** backend_src = $(top_srcdir)/src/backend
  # For port modules, this only happens if configure decides the module
  # is needed (see filter hack in OBJS, above).
  
! crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
  	rm -f $@ && $(LN_S) $< .
  
  md5.c ip.c: % : $(backend_src)/libpq/%
--- 80,86 ----
  # For port modules, this only happens if configure decides the module
  # is needed (see filter hack in OBJS, above).
  
! crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
  	rm -f $@ && $(LN_S) $< .
  
  md5.c ip.c: % : $(backend_src)/libpq/%
***************
*** 123,129 **** uninstall: uninstall-lib
  	rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'
  
  clean distclean: clean-lib
! 	rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
  # Might be left over from a Win32 client-only build
  	rm -f pg_config_paths.h
  
--- 123,129 ----
  	rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'
  
  clean distclean: clean-lib
! 	rm -f $(OBJS) pg_config_paths.h crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
  # Might be left over from a Win32 client-only build
  	rm -f pg_config_paths.h
  
*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***************
*** 63,68 ****
--- 63,73 ----
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
  #include <openssl/engine.h>
  #endif
+ 
+ /* fnmatch() needed for client certificate mapping */
+ #ifdef HAVE_FNMATCH
+ #include <fnmatch.h>
+ #endif
  #endif   /* USE_SSL */
  
  
***************
*** 461,477 **** verify_peer_name_matches_certificate(PGconn *conn)
  		 * Connect by hostname.
  		 *
  		 * XXX: Should support alternate names here
- 		 * XXX: Should support wildcard certificates here
  		 */
! 		if (pg_strcasecmp(conn->peer_cn, conn->pghost) != 0)
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("server common name '%s' does not match hostname '%s'"),
  							  conn->peer_cn, conn->pghost);
  			return false;
  		}
- 		else
- 			return true;
  	}
  }
  
--- 466,485 ----
  		 * Connect by hostname.
  		 *
  		 * XXX: Should support alternate names here
  		 */
! 		if (pg_strcasecmp(conn->peer_cn, conn->pghost) == 0)
! 			/* Exact name match */
! 			return true;
! 		else if (fnmatch(conn->peer_cn, conn->pghost, FNM_NOESCAPE | FNM_CASEFOLD) == 0)
! 			/* Matched wildcard certificate */
! 			return true;
! 		else
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("server common name '%s' does not match hostname '%s'"),
  							  conn->peer_cn, conn->pghost);
  			return false;
  		}
  	}
  }
  
*** /dev/null
--- b/src/port/fnmatch.c
***************
*** 0 ****
--- 1,197 ----
+ /*-------------------------------------------------------------------------
+  *
+  * fnmatch.c
+  *        fnmatch() - wildcard matching function
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *        $PostgreSQL$
+  *
+  * This file was taken from NetBSD and is used on platforms that don't
+  * provide fnmatch(). The NetBSD copyright terms follow.
+  *-------------------------------------------------------------------------
+  */
+ 
+ /*	$NetBSD: fnmatch.c,v 1.21 2005/12/24 21:11:16 perry Exp $	*/
+ 
+ /*
+  * Copyright (c) 1989, 1993, 1994
+  *	The Regents of the University of California.  All rights reserved.
+  *
+  * This code is derived from software contributed to Berkeley by
+  * Guido van Rossum.
+  *
+  * 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.
+  * 3. 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.
+  */
+ 
+ /*
+  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+  * Compares a filename or pathname to a pattern.
+  */
+ 
+ #include "c.h"
+ 
+ #define	EOS	'\0'
+ 
+ static const char *rangematch (const char *, int, int);
+ 
+ static inline int
+ foldcase(int ch, int flags)
+ {
+ 
+ 	if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
+ 		return (tolower(ch));
+ 	return (ch);
+ }
+ 
+ #define	FOLDCASE(ch, flags)	foldcase((unsigned char)(ch), (flags))
+ 
+ int
+ fnmatch(pattern, string, flags)
+ 	const char *pattern, *string;
+ 	int flags;
+ {
+ 	const char *stringstart;
+ 	char c, test;
+ 
+ 	for (stringstart = string;;)
+ 		switch (c = FOLDCASE(*pattern++, flags)) {
+ 		case EOS:
+ 			if ((flags & FNM_LEADING_DIR) && *string == '/')
+ 				return (0);
+ 			return (*string == EOS ? 0 : FNM_NOMATCH);
+ 		case '?':
+ 			if (*string == EOS)
+ 				return (FNM_NOMATCH);
+ 			if (*string == '/' && (flags & FNM_PATHNAME))
+ 				return (FNM_NOMATCH);
+ 			if (*string == '.' && (flags & FNM_PERIOD) &&
+ 			    (string == stringstart ||
+ 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ 				return (FNM_NOMATCH);
+ 			++string;
+ 			break;
+ 		case '*':
+ 			c = FOLDCASE(*pattern, flags);
+ 			/* Collapse multiple stars. */
+ 			while (c == '*')
+ 				c = FOLDCASE(*++pattern, flags);
+ 
+ 			if (*string == '.' && (flags & FNM_PERIOD) &&
+ 			    (string == stringstart ||
+ 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ 				return (FNM_NOMATCH);
+ 
+ 			/* Optimize for pattern with * at end or before /. */
+ 			if (c == EOS) {
+ 				if (flags & FNM_PATHNAME)
+ 					return ((flags & FNM_LEADING_DIR) ||
+ 					    strchr(string, '/') == NULL ?
+ 					    0 : FNM_NOMATCH);
+ 				else
+ 					return (0);
+ 			} else if (c == '/' && flags & FNM_PATHNAME) {
+ 				if ((string = strchr(string, '/')) == NULL)
+ 					return (FNM_NOMATCH);
+ 				break;
+ 			}
+ 
+ 			/* General case, use recursion. */
+ 			while ((test = FOLDCASE(*string, flags)) != EOS) {
+ 				if (!fnmatch(pattern, string,
+ 					     flags & ~FNM_PERIOD))
+ 					return (0);
+ 				if (test == '/' && flags & FNM_PATHNAME)
+ 					break;
+ 				++string;
+ 			}
+ 			return (FNM_NOMATCH);
+ 		case '[':
+ 			if (*string == EOS)
+ 				return (FNM_NOMATCH);
+ 			if (*string == '/' && flags & FNM_PATHNAME)
+ 				return (FNM_NOMATCH);
+ 			if ((pattern =
+ 			    rangematch(pattern, FOLDCASE(*string, flags),
+ 				       flags)) == NULL)
+ 				return (FNM_NOMATCH);
+ 			++string;
+ 			break;
+ 		case '\\':
+ 			if (!(flags & FNM_NOESCAPE)) {
+ 				if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
+ 					c = '\\';
+ 					--pattern;
+ 				}
+ 			}
+ 			/* FALLTHROUGH */
+ 		default:
+ 			if (c != FOLDCASE(*string++, flags))
+ 				return (FNM_NOMATCH);
+ 			break;
+ 		}
+ 	/* NOTREACHED */
+ }
+ 
+ static const char *
+ rangematch(pattern, test, flags)
+ 	const char *pattern;
+ 	int test, flags;
+ {
+ 	int negate, ok;
+ 	char c, c2;
+ 
+ 	/*
+ 	 * A bracket expression starting with an unquoted circumflex
+ 	 * character produces unspecified results (IEEE 1003.2-1992,
+ 	 * 3.13.2).  This implementation treats it like '!', for
+ 	 * consistency with the regular expression syntax.
+ 	 * J.T. Conklin (conklin@ngai.kaleida.com)
+ 	 */
+ 	if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
+ 		++pattern;
+ 	
+ 	for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
+ 		if (c == '\\' && !(flags & FNM_NOESCAPE))
+ 			c = FOLDCASE(*pattern++, flags);
+ 		if (c == EOS)
+ 			return (NULL);
+ 		if (*pattern == '-' 
+ 		    && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
+ 		        c2 != ']') {
+ 			pattern += 2;
+ 			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
+ 				c2 = FOLDCASE(*pattern++, flags);
+ 			if (c2 == EOS)
+ 				return (NULL);
+ 			if (c <= test && test <= c2)
+ 				ok = 1;
+ 		} else if (c == test)
+ 			ok = 1;
+ 	}
+ 	return (ok == negate ? NULL : pattern);
+ }
#4Magnus Hagander
magnus@hagander.net
In reply to: Magnus Hagander (#3)
1 attachment(s)
Re: Autoconf, libpq and replacement function

Magnus Hagander wrote:

Peter Eisentraut wrote:

Magnus Hagander wrote:

How do I make this work with the autoconf magic? I see there is an
AC_CHECK_FNMATCH and AC_REPLACE_FNMATCH and so, but I have a feeling I
need to do something different since it's libpq?

AC_*_FNMATCH will figure out whether you need fnmatch(), so something
involving those is necessary.

For libpq, check libpq's Makefile for, say, snprintf, to get an idea
about the "something different".

Altogether, this might not be a trivial case.

Hmm. If I did it the right way, it actually didn't seem too hard once I
found a good example. Attached - does that seem reasonable?

(will add msvc code as well)

That was easy. I also reversed the accidentally-reversed #ifdef in port.h.

//Mangus

Attachments:

wildcard_cert.difftext/x-diff; name=wildcard_cert.diffDownload
*** a/configure
--- b/configure
***************
*** 16930,16936 **** LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
  
  
  
! for ac_func in crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul unsetenv
  do
  as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
  { echo "$as_me:$LINENO: checking for $ac_func" >&5
--- 16930,16937 ----
  
  
  
! 
! for ac_func in crypt fnmatch getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul unsetenv
  do
  as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
  { echo "$as_me:$LINENO: checking for $ac_func" >&5
*** a/configure.in
--- b/configure.in
***************
*** 1235,1241 **** fi
  pgac_save_LIBS="$LIBS"
  LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
  
! AC_REPLACE_FUNCS([crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul unsetenv])
  
  LIBS="$pgac_save_LIBS"
  
--- 1235,1241 ----
  pgac_save_LIBS="$LIBS"
  LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
  
! AC_REPLACE_FUNCS([crypt fnmatch getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul unsetenv])
  
  LIBS="$pgac_save_LIBS"
  
*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 143,148 ****
--- 143,151 ----
  /* Define to 1 if you have the `fdatasync' function. */
  #undef HAVE_FDATASYNC
  
+ /* Define to 1 if you have the `fnmatch' function. */
+ #undef HAVE_FNMATCH
+ 
  /* Define to 1 if you have the `fpclass' function. */
  #undef HAVE_FPCLASS
  
*** a/src/include/port.h
--- b/src/include/port.h
***************
*** 393,398 **** extern void unsetenv(const char *name);
--- 393,409 ----
  extern void srandom(unsigned int seed);
  #endif
  
+ #ifndef HAVE_FNMATCH
+ extern int fnmatch(const char *, const char *, int);
+ #define FNM_NOMATCH		1		/* Match failed. */
+ #define FNM_NOSYS		2		/* Function not implemented. */
+ #define FNM_NOESCAPE	0x01	/* Disable backslash escaping. */
+ #define FNM_PATHNAME	0x02	/* Slash must be matched by slash. */
+ #define FNM_PERIOD		0x04	/* Period must be matched by period. */
+ #define FNM_CASEFOLD	0x08	/* Pattern is matched case-insensitive */
+ #define FNM_LEADING_DIR	0x10	/* Ignore /<tail> after Imatch. */
+ #endif
+ 
  /* thread.h */
  extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen);
  
*** a/src/interfaces/libpq/Makefile
--- b/src/interfaces/libpq/Makefile
***************
*** 34,40 **** OBJS=	fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
  	fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
  	libpq-events.o \
  	md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
! 	$(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
  
  ifeq ($(PORTNAME), cygwin)
  override shlib = cyg$(NAME)$(DLSUFFIX)
--- 34,40 ----
  	fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
  	libpq-events.o \
  	md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
! 	$(filter crypt.o fnmatch.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
  
  ifeq ($(PORTNAME), cygwin)
  override shlib = cyg$(NAME)$(DLSUFFIX)
***************
*** 80,86 **** backend_src = $(top_srcdir)/src/backend
  # For port modules, this only happens if configure decides the module
  # is needed (see filter hack in OBJS, above).
  
! crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
  	rm -f $@ && $(LN_S) $< .
  
  md5.c ip.c: % : $(backend_src)/libpq/%
--- 80,86 ----
  # For port modules, this only happens if configure decides the module
  # is needed (see filter hack in OBJS, above).
  
! crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
  	rm -f $@ && $(LN_S) $< .
  
  md5.c ip.c: % : $(backend_src)/libpq/%
***************
*** 123,129 **** uninstall: uninstall-lib
  	rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'
  
  clean distclean: clean-lib
! 	rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
  # Might be left over from a Win32 client-only build
  	rm -f pg_config_paths.h
  
--- 123,129 ----
  	rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'
  
  clean distclean: clean-lib
! 	rm -f $(OBJS) pg_config_paths.h crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
  # Might be left over from a Win32 client-only build
  	rm -f pg_config_paths.h
  
*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***************
*** 63,68 ****
--- 63,73 ----
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
  #include <openssl/engine.h>
  #endif
+ 
+ /* fnmatch() needed for client certificate mapping */
+ #ifdef HAVE_FNMATCH
+ #include <fnmatch.h>
+ #endif
  #endif   /* USE_SSL */
  
  
***************
*** 461,477 **** verify_peer_name_matches_certificate(PGconn *conn)
  		 * Connect by hostname.
  		 *
  		 * XXX: Should support alternate names here
- 		 * XXX: Should support wildcard certificates here
  		 */
! 		if (pg_strcasecmp(conn->peer_cn, conn->pghost) != 0)
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("server common name '%s' does not match hostname '%s'"),
  							  conn->peer_cn, conn->pghost);
  			return false;
  		}
- 		else
- 			return true;
  	}
  }
  
--- 466,485 ----
  		 * Connect by hostname.
  		 *
  		 * XXX: Should support alternate names here
  		 */
! 		if (pg_strcasecmp(conn->peer_cn, conn->pghost) == 0)
! 			/* Exact name match */
! 			return true;
! 		else if (fnmatch(conn->peer_cn, conn->pghost, FNM_NOESCAPE | FNM_CASEFOLD) == 0)
! 			/* Matched wildcard certificate */
! 			return true;
! 		else
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("server common name '%s' does not match hostname '%s'"),
  							  conn->peer_cn, conn->pghost);
  			return false;
  		}
  	}
  }
  
*** /dev/null
--- b/src/port/fnmatch.c
***************
*** 0 ****
--- 1,197 ----
+ /*-------------------------------------------------------------------------
+  *
+  * fnmatch.c
+  *        fnmatch() - wildcard matching function
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *        $PostgreSQL$
+  *
+  * This file was taken from NetBSD and is used on platforms that don't
+  * provide fnmatch(). The NetBSD copyright terms follow.
+  *-------------------------------------------------------------------------
+  */
+ 
+ /*	$NetBSD: fnmatch.c,v 1.21 2005/12/24 21:11:16 perry Exp $	*/
+ 
+ /*
+  * Copyright (c) 1989, 1993, 1994
+  *	The Regents of the University of California.  All rights reserved.
+  *
+  * This code is derived from software contributed to Berkeley by
+  * Guido van Rossum.
+  *
+  * 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.
+  * 3. 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.
+  */
+ 
+ /*
+  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+  * Compares a filename or pathname to a pattern.
+  */
+ 
+ #include "c.h"
+ 
+ #define	EOS	'\0'
+ 
+ static const char *rangematch (const char *, int, int);
+ 
+ static inline int
+ foldcase(int ch, int flags)
+ {
+ 
+ 	if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
+ 		return (tolower(ch));
+ 	return (ch);
+ }
+ 
+ #define	FOLDCASE(ch, flags)	foldcase((unsigned char)(ch), (flags))
+ 
+ int
+ fnmatch(pattern, string, flags)
+ 	const char *pattern, *string;
+ 	int flags;
+ {
+ 	const char *stringstart;
+ 	char c, test;
+ 
+ 	for (stringstart = string;;)
+ 		switch (c = FOLDCASE(*pattern++, flags)) {
+ 		case EOS:
+ 			if ((flags & FNM_LEADING_DIR) && *string == '/')
+ 				return (0);
+ 			return (*string == EOS ? 0 : FNM_NOMATCH);
+ 		case '?':
+ 			if (*string == EOS)
+ 				return (FNM_NOMATCH);
+ 			if (*string == '/' && (flags & FNM_PATHNAME))
+ 				return (FNM_NOMATCH);
+ 			if (*string == '.' && (flags & FNM_PERIOD) &&
+ 			    (string == stringstart ||
+ 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ 				return (FNM_NOMATCH);
+ 			++string;
+ 			break;
+ 		case '*':
+ 			c = FOLDCASE(*pattern, flags);
+ 			/* Collapse multiple stars. */
+ 			while (c == '*')
+ 				c = FOLDCASE(*++pattern, flags);
+ 
+ 			if (*string == '.' && (flags & FNM_PERIOD) &&
+ 			    (string == stringstart ||
+ 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ 				return (FNM_NOMATCH);
+ 
+ 			/* Optimize for pattern with * at end or before /. */
+ 			if (c == EOS) {
+ 				if (flags & FNM_PATHNAME)
+ 					return ((flags & FNM_LEADING_DIR) ||
+ 					    strchr(string, '/') == NULL ?
+ 					    0 : FNM_NOMATCH);
+ 				else
+ 					return (0);
+ 			} else if (c == '/' && flags & FNM_PATHNAME) {
+ 				if ((string = strchr(string, '/')) == NULL)
+ 					return (FNM_NOMATCH);
+ 				break;
+ 			}
+ 
+ 			/* General case, use recursion. */
+ 			while ((test = FOLDCASE(*string, flags)) != EOS) {
+ 				if (!fnmatch(pattern, string,
+ 					     flags & ~FNM_PERIOD))
+ 					return (0);
+ 				if (test == '/' && flags & FNM_PATHNAME)
+ 					break;
+ 				++string;
+ 			}
+ 			return (FNM_NOMATCH);
+ 		case '[':
+ 			if (*string == EOS)
+ 				return (FNM_NOMATCH);
+ 			if (*string == '/' && flags & FNM_PATHNAME)
+ 				return (FNM_NOMATCH);
+ 			if ((pattern =
+ 			    rangematch(pattern, FOLDCASE(*string, flags),
+ 				       flags)) == NULL)
+ 				return (FNM_NOMATCH);
+ 			++string;
+ 			break;
+ 		case '\\':
+ 			if (!(flags & FNM_NOESCAPE)) {
+ 				if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
+ 					c = '\\';
+ 					--pattern;
+ 				}
+ 			}
+ 			/* FALLTHROUGH */
+ 		default:
+ 			if (c != FOLDCASE(*string++, flags))
+ 				return (FNM_NOMATCH);
+ 			break;
+ 		}
+ 	/* NOTREACHED */
+ }
+ 
+ static const char *
+ rangematch(pattern, test, flags)
+ 	const char *pattern;
+ 	int test, flags;
+ {
+ 	int negate, ok;
+ 	char c, c2;
+ 
+ 	/*
+ 	 * A bracket expression starting with an unquoted circumflex
+ 	 * character produces unspecified results (IEEE 1003.2-1992,
+ 	 * 3.13.2).  This implementation treats it like '!', for
+ 	 * consistency with the regular expression syntax.
+ 	 * J.T. Conklin (conklin@ngai.kaleida.com)
+ 	 */
+ 	if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
+ 		++pattern;
+ 	
+ 	for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
+ 		if (c == '\\' && !(flags & FNM_NOESCAPE))
+ 			c = FOLDCASE(*pattern++, flags);
+ 		if (c == EOS)
+ 			return (NULL);
+ 		if (*pattern == '-' 
+ 		    && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
+ 		        c2 != ']') {
+ 			pattern += 2;
+ 			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
+ 				c2 = FOLDCASE(*pattern++, flags);
+ 			if (c2 == EOS)
+ 				return (NULL);
+ 			if (c <= test && test <= c2)
+ 				ok = 1;
+ 		} else if (c == test)
+ 			ok = 1;
+ 	}
+ 	return (ok == negate ? NULL : pattern);
+ }
*** a/src/tools/msvc/Mkvcbuild.pm
--- b/src/tools/msvc/Mkvcbuild.pm
***************
*** 43,49 **** sub mkvcbuild
      $solution = new Solution($config);
  
      our @pgportfiles = qw(
!       chklocale.c crypt.c fseeko.c getrusage.c inet_aton.c random.c srandom.c
        unsetenv.c getaddrinfo.c gettimeofday.c kill.c open.c rand.c
        snprintf.c strlcat.c strlcpy.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c
        pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c
--- 43,49 ----
      $solution = new Solution($config);
  
      our @pgportfiles = qw(
!       chklocale.c crypt.c fseeko.c fnmatch.c getrusage.c inet_aton.c random.c srandom.c
        unsetenv.c getaddrinfo.c gettimeofday.c kill.c open.c rand.c
        snprintf.c strlcat.c strlcpy.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c
        pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c
#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#3)
Re: Autoconf, libpq and replacement function

Magnus Hagander <magnus@hagander.net> writes:

*** a/src/include/port.h
--- b/src/include/port.h
***************
*** 393,398 **** extern void unsetenv(const char *name);
--- 393,409 ----
extern void srandom(unsigned int seed);
#endif
+ #ifdef HAVE_FNMATCH
+ extern int fnmatch(const char *, const char *, int);
+ #define FNM_NOMATCH		1		/* Match failed. */
+ #define FNM_NOSYS		2		/* Function not implemented. */
+ #define FNM_NOESCAPE	0x01	/* Disable backslash escaping. */
+ #define FNM_PATHNAME	0x02	/* Slash must be matched by slash. */
+ #define FNM_PERIOD		0x04	/* Period must be matched by period. */
+ #define FNM_CASEFOLD	0x08	/* Pattern is matched case-insensitive */
+ #define FNM_LEADING_DIR	0x10	/* Ignore /<tail> after Imatch. */
+ #endif
+ 

Surely we must *not* be providing our own definitions of these symbols
when using a system version of fnmatch.

Also, judging from the comments in the autoconf manual, you'd better
use AC_FUNC_FNMATCH not just test whether the function exists.

regards, tom lane

#6Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#5)
Re: Autoconf, libpq and replacement function

Tom Lane wrote:

Magnus Hagander <magnus@hagander.net> writes:

*** a/src/include/port.h
--- b/src/include/port.h
***************
*** 393,398 **** extern void unsetenv(const char *name);
--- 393,409 ----
extern void srandom(unsigned int seed);
#endif
+ #ifdef HAVE_FNMATCH
+ extern int fnmatch(const char *, const char *, int);
+ #define FNM_NOMATCH		1		/* Match failed. */
+ #define FNM_NOSYS		2		/* Function not implemented. */
+ #define FNM_NOESCAPE	0x01	/* Disable backslash escaping. */
+ #define FNM_PATHNAME	0x02	/* Slash must be matched by slash. */
+ #define FNM_PERIOD		0x04	/* Period must be matched by period. */
+ #define FNM_CASEFOLD	0x08	/* Pattern is matched case-insensitive */
+ #define FNM_LEADING_DIR	0x10	/* Ignore /<tail> after Imatch. */
+ #endif
+ 

Surely we must *not* be providing our own definitions of these symbols
when using a system version of fnmatch.

That's the define that I reversed in the second patch I sent. It's
supposed to be ifndef.

Also, judging from the comments in the autoconf manual, you'd better
use AC_FUNC_FNMATCH not just test whether the function exists.

Ok, will look at switching to that.

//Magnus

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#6)
Re: Autoconf, libpq and replacement function

Magnus Hagander <magnus@hagander.net> writes:

Tom Lane wrote:

Surely we must *not* be providing our own definitions of these symbols
when using a system version of fnmatch.

That's the define that I reversed in the second patch I sent. It's
supposed to be ifndef.

Okay.

Also, judging from the comments in the autoconf manual, you'd better
use AC_FUNC_FNMATCH not just test whether the function exists.

Ok, will look at switching to that.

Hmm ... actually there's still possibly an issue there: what if the
system provides a broken version of fnmatch? AC_FUNC_FNMATCH will not
set HAVE_FNMATCH, and then we might end up with #define conflicts
anyway.

Since fnmatch and the #define's are supposed to be provided by
<fnmatch.h>, I think you should probably put the substitute definitions
in a substitute fnmatch.h, not port.h, to avoid that risk.

regards, tom lane

#8Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#7)
Re: Autoconf, libpq and replacement function

Tom Lane wrote:

Magnus Hagander <magnus@hagander.net> writes:

Also, judging from the comments in the autoconf manual, you'd better
use AC_FUNC_FNMATCH not just test whether the function exists.

Ok, will look at switching to that.

Hmm ... actually there's still possibly an issue there: what if the
system provides a broken version of fnmatch? AC_FUNC_FNMATCH will not
set HAVE_FNMATCH, and then we might end up with #define conflicts
anyway.

Since fnmatch and the #define's are supposed to be provided by
<fnmatch.h>, I think you should probably put the substitute definitions
in a substitute fnmatch.h, not port.h, to avoid that risk.

Do we have an example where we do that before? I assume there is some
autoconfy way to make that include file only "appear" in the include
path if the system one doesn't exist or is broken?

//Magnus

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#8)
Re: Autoconf, libpq and replacement function

Magnus Hagander <magnus@hagander.net> writes:

Tom Lane wrote:

Since fnmatch and the #define's are supposed to be provided by
<fnmatch.h>, I think you should probably put the substitute definitions
in a substitute fnmatch.h, not port.h, to avoid that risk.

Do we have an example where we do that before? I assume there is some
autoconfy way to make that include file only "appear" in the include
path if the system one doesn't exist or is broken?

Not really. I'd suggest making the callers do something like

#ifdef HAVE_FNMATCH
#include <fnmatch.h>
#else
#include "port/pg_fnmatch.h"
#endif

regards, tom lane

#10Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#9)
Re: Autoconf, libpq and replacement function

Tom Lane wrote:

Magnus Hagander <magnus@hagander.net> writes:

Tom Lane wrote:

Since fnmatch and the #define's are supposed to be provided by
<fnmatch.h>, I think you should probably put the substitute definitions
in a substitute fnmatch.h, not port.h, to avoid that risk.

Do we have an example where we do that before? I assume there is some
autoconfy way to make that include file only "appear" in the include
path if the system one doesn't exist or is broken?

Not really. I'd suggest making the callers do something like

#ifdef HAVE_FNMATCH
#include <fnmatch.h>
#else
#include "port/pg_fnmatch.h"
#endif

How's that actually different from the
#ifdef HAVE_FNMATCH
#include <fnmatch.h> <-- happens in fe-secure.c
#else
#define .... <-- happens in port.h
#endif

If HAVE_FNMATCH isn't set, we still have the same problem, no?

//Magnus

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#10)
Re: Autoconf, libpq and replacement function

Magnus Hagander <magnus@hagander.net> writes:

Tom Lane wrote:

Not really. I'd suggest making the callers do something like

#ifdef HAVE_FNMATCH
#include <fnmatch.h>
#else
#include "port/pg_fnmatch.h"
#endif

How's that actually different from the
#ifdef HAVE_FNMATCH
#include <fnmatch.h> <-- happens in fe-secure.c
#else
#define .... <-- happens in port.h
#endif

What's bothering me is that port.h gets included *everywhere*, and
might perhaps conflict with some indirect or accidental inclusion
of <fnmatch.h>.

It would also allow someone to forget the
#ifdef HAVE_FNMATCH
#include <fnmatch.h>
#endif
part and have it still work, if they were testing on a broken platform.
It's better that both inclusions appear together instead of having the
alternative code paths effectively appear in two unrelated files.

regards, tom lane

#12Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#11)
Re: Autoconf, libpq and replacement function

Tom Lane wrote:

Magnus Hagander <magnus@hagander.net> writes:

Tom Lane wrote:

Not really. I'd suggest making the callers do something like

#ifdef HAVE_FNMATCH
#include <fnmatch.h>
#else
#include "port/pg_fnmatch.h"
#endif

How's that actually different from the
#ifdef HAVE_FNMATCH
#include <fnmatch.h> <-- happens in fe-secure.c
#else
#define .... <-- happens in port.h
#endif

What's bothering me is that port.h gets included *everywhere*, and
might perhaps conflict with some indirect or accidental inclusion
of <fnmatch.h>.

It would also allow someone to forget the
#ifdef HAVE_FNMATCH
#include <fnmatch.h>
#endif
part and have it still work, if they were testing on a broken platform.
It's better that both inclusions appear together instead of having the
alternative code paths effectively appear in two unrelated files.

Ok, I see your argument now.

AFAICS, we're not doing this for any other functions though - or am I
too tired and just looking in the wrong place? Or is that because
they're just function definitions and not #defines?

(I want to be sure to stick whatever new file there is in the same place..)

//Magnus

#13Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#12)
Re: Autoconf, libpq and replacement function

Magnus Hagander <magnus@hagander.net> writes:

AFAICS, we're not doing this for any other functions though - or am I
too tired and just looking in the wrong place? Or is that because
they're just function definitions and not #defines?
(I want to be sure to stick whatever new file there is in the same place..)

src/include/rusagestub.h is doing things more or less this way.

Also, right now we have got

src/include/getaddrinfo.h
src/include/getopt_long.h

which really make me itch now that I am contemplating the possibility
that we try to use libc-supplied code for these functions along with
our own header definitions.

I think the reason we've avoided putting such stuff into include/port/
is that right now that directory consists exclusively of OS-specific
files. Maybe we need another include subdirectory?

regards, tom lane

#14Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#13)
1 attachment(s)
Re: Autoconf, libpq and replacement function

Tom Lane wrote:

Magnus Hagander <magnus@hagander.net> writes:

AFAICS, we're not doing this for any other functions though - or am I
too tired and just looking in the wrong place? Or is that because
they're just function definitions and not #defines?
(I want to be sure to stick whatever new file there is in the same place..)

src/include/rusagestub.h is doing things more or less this way.

Also, right now we have got

src/include/getaddrinfo.h
src/include/getopt_long.h

which really make me itch now that I am contemplating the possibility
that we try to use libc-supplied code for these functions along with
our own header definitions.

I think the reason we've avoided putting such stuff into include/port/
is that right now that directory consists exclusively of OS-specific
files. Maybe we need another include subdirectory?

Or in the same directly, called something else. Like fnmatchstub.h. See
attached, seems reasonable?

//Magnus

Attachments:

wildcard_cert.difftext/x-diff; name=wildcard_cert.diffDownload
*** a/configure
--- b/configure
***************
*** 24821,24826 **** esac
--- 24821,24910 ----
  
  
  
+ # Check for fnmatch()
+ { echo "$as_me:$LINENO: checking for working POSIX fnmatch" >&5
+ echo $ECHO_N "checking for working POSIX fnmatch... $ECHO_C" >&6; }
+ if test "${ac_cv_func_fnmatch_works+set}" = set; then
+   echo $ECHO_N "(cached) $ECHO_C" >&6
+ else
+   # Some versions of Solaris, SCO, and the GNU C Library
+    # have a broken or incompatible fnmatch.
+    # So we run a test program.  If we are cross-compiling, take no chance.
+    # Thanks to John Oleynick, Franc,ois Pinard, and Paul Eggert for this test.
+    if test "$cross_compiling" = yes; then
+   ac_cv_func_fnmatch_works=cross
+ else
+   cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h.  */
+ _ACEOF
+ cat confdefs.h >>conftest.$ac_ext
+ cat >>conftest.$ac_ext <<_ACEOF
+ /* end confdefs.h.  */
+ #include <fnmatch.h>
+ #	   define y(a, b, c) (fnmatch (a, b, c) == 0)
+ #	   define n(a, b, c) (fnmatch (a, b, c) == FNM_NOMATCH)
+ 
+ int
+ main ()
+ {
+ return
+ 	   (!(y ("a*", "abc", 0)
+ 	      && n ("d*/*1", "d/s/1", FNM_PATHNAME)
+ 	      && y ("a\\\\bc", "abc", 0)
+ 	      && n ("a\\\\bc", "abc", FNM_NOESCAPE)
+ 	      && y ("*x", ".x", 0)
+ 	      && n ("*x", ".x", FNM_PERIOD)
+ 	      && 1));
+   ;
+   return 0;
+ }
+ _ACEOF
+ rm -f conftest$ac_exeext
+ if { (ac_try="$ac_link"
+ case "(($ac_try" in
+   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+   *) ac_try_echo=$ac_try;;
+ esac
+ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+   (eval "$ac_link") 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+   { (case "(($ac_try" in
+   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+   *) ac_try_echo=$ac_try;;
+ esac
+ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+   (eval "$ac_try") 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); }; }; then
+   ac_cv_func_fnmatch_works=yes
+ else
+   echo "$as_me: program exited with status $ac_status" >&5
+ echo "$as_me: failed program was:" >&5
+ sed 's/^/| /' conftest.$ac_ext >&5
+ 
+ ( exit $ac_status )
+ ac_cv_func_fnmatch_works=no
+ fi
+ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+ fi
+ 
+ 
+ fi
+ { echo "$as_me:$LINENO: result: $ac_cv_func_fnmatch_works" >&5
+ echo "${ECHO_T}$ac_cv_func_fnmatch_works" >&6; }
+ if test $ac_cv_func_fnmatch_works = yes; then
+ 
+ cat >>confdefs.h <<\_ACEOF
+ #define HAVE_FNMATCH 1
+ _ACEOF
+ 
+ fi
+ 
+ 
+ 
  
  # Select semaphore implementation type.
  if test "$PORTNAME" != "win32"; then
*** a/configure.in
--- b/configure.in
***************
*** 1625,1630 **** fi
--- 1625,1632 ----
  # SunOS doesn't handle negative byte comparisons properly with +/- return
  AC_FUNC_MEMCMP
  
+ # Check for fnmatch()
+ AC_FUNC_FNMATCH
  
  # Select semaphore implementation type.
  if test "$PORTNAME" != "win32"; then
*** /dev/null
--- b/src/include/fnmatchstub.h
***************
*** 0 ****
--- 1,27 ----
+ /*-------------------------------------------------------------------------
+  *
+  * fnmatchstub.h
+  *	  Stubs for fnmatch() in port/fnmatch.c
+  *
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef FNMATCHSTUB_H
+ #define FNMATCHSTUB_H
+ 
+ extern int fnmatch(const char *, const char *, int);
+ #define FNM_NOMATCH		1		/* Match failed. */
+ #define FNM_NOSYS		2		/* Function not implemented. */
+ #define FNM_NOESCAPE	0x01	/* Disable backslash escaping. */
+ #define FNM_PATHNAME	0x02	/* Slash must be matched by slash. */
+ #define FNM_PERIOD		0x04	/* Period must be matched by period. */
+ #define FNM_CASEFOLD	0x08	/* Pattern is matched case-insensitive */
+ #define FNM_LEADING_DIR	0x10	/* Ignore /<tail> after Imatch. */
+ 
+ 
+ #endif
*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 143,148 ****
--- 143,151 ----
  /* Define to 1 if you have the `fdatasync' function. */
  #undef HAVE_FDATASYNC
  
+ /* Define to 1 if your system has a working POSIX `fnmatch' function. */
+ #undef HAVE_FNMATCH
+ 
  /* Define to 1 if you have the `fpclass' function. */
  #undef HAVE_FPCLASS
  
*** a/src/interfaces/libpq/Makefile
--- b/src/interfaces/libpq/Makefile
***************
*** 34,40 **** OBJS=	fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
  	fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
  	libpq-events.o \
  	md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
! 	$(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
  
  ifeq ($(PORTNAME), cygwin)
  override shlib = cyg$(NAME)$(DLSUFFIX)
--- 34,40 ----
  	fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
  	libpq-events.o \
  	md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
! 	$(filter crypt.o fnmatch.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
  
  ifeq ($(PORTNAME), cygwin)
  override shlib = cyg$(NAME)$(DLSUFFIX)
***************
*** 80,86 **** backend_src = $(top_srcdir)/src/backend
  # For port modules, this only happens if configure decides the module
  # is needed (see filter hack in OBJS, above).
  
! crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
  	rm -f $@ && $(LN_S) $< .
  
  md5.c ip.c: % : $(backend_src)/libpq/%
--- 80,86 ----
  # For port modules, this only happens if configure decides the module
  # is needed (see filter hack in OBJS, above).
  
! crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
  	rm -f $@ && $(LN_S) $< .
  
  md5.c ip.c: % : $(backend_src)/libpq/%
***************
*** 123,129 **** uninstall: uninstall-lib
  	rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'
  
  clean distclean: clean-lib
! 	rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
  # Might be left over from a Win32 client-only build
  	rm -f pg_config_paths.h
  
--- 123,129 ----
  	rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'
  
  clean distclean: clean-lib
! 	rm -f $(OBJS) pg_config_paths.h crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
  # Might be left over from a Win32 client-only build
  	rm -f pg_config_paths.h
  
*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***************
*** 63,68 ****
--- 63,75 ----
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
  #include <openssl/engine.h>
  #endif
+ 
+ /* fnmatch() needed for client certificate mapping */
+ #ifdef HAVE_FNMATCH
+ #include <fnmatch.h>
+ #else
+ #include "fnmatchstub.h"
+ #endif
  #endif   /* USE_SSL */
  
  
***************
*** 461,477 **** verify_peer_name_matches_certificate(PGconn *conn)
  		 * Connect by hostname.
  		 *
  		 * XXX: Should support alternate names here
- 		 * XXX: Should support wildcard certificates here
  		 */
! 		if (pg_strcasecmp(conn->peer_cn, conn->pghost) != 0)
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("server common name '%s' does not match hostname '%s'"),
  							  conn->peer_cn, conn->pghost);
  			return false;
  		}
- 		else
- 			return true;
  	}
  }
  
--- 468,487 ----
  		 * Connect by hostname.
  		 *
  		 * XXX: Should support alternate names here
  		 */
! 		if (pg_strcasecmp(conn->peer_cn, conn->pghost) == 0)
! 			/* Exact name match */
! 			return true;
! 		else if (fnmatch(conn->peer_cn, conn->pghost, FNM_NOESCAPE | FNM_CASEFOLD) == 0)
! 			/* Matched wildcard certificate */
! 			return true;
! 		else
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("server common name '%s' does not match hostname '%s'"),
  							  conn->peer_cn, conn->pghost);
  			return false;
  		}
  	}
  }
  
*** /dev/null
--- b/src/port/fnmatch.c
***************
*** 0 ****
--- 1,197 ----
+ /*-------------------------------------------------------------------------
+  *
+  * fnmatch.c
+  *        fnmatch() - wildcard matching function
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *        $PostgreSQL$
+  *
+  * This file was taken from NetBSD and is used on platforms that don't
+  * provide fnmatch(). The NetBSD copyright terms follow.
+  *-------------------------------------------------------------------------
+  */
+ 
+ /*	$NetBSD: fnmatch.c,v 1.21 2005/12/24 21:11:16 perry Exp $	*/
+ 
+ /*
+  * Copyright (c) 1989, 1993, 1994
+  *	The Regents of the University of California.  All rights reserved.
+  *
+  * This code is derived from software contributed to Berkeley by
+  * Guido van Rossum.
+  *
+  * 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.
+  * 3. 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.
+  */
+ 
+ /*
+  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+  * Compares a filename or pathname to a pattern.
+  */
+ 
+ #include "c.h"
+ 
+ #define	EOS	'\0'
+ 
+ static const char *rangematch (const char *, int, int);
+ 
+ static inline int
+ foldcase(int ch, int flags)
+ {
+ 
+ 	if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
+ 		return (tolower(ch));
+ 	return (ch);
+ }
+ 
+ #define	FOLDCASE(ch, flags)	foldcase((unsigned char)(ch), (flags))
+ 
+ int
+ fnmatch(pattern, string, flags)
+ 	const char *pattern, *string;
+ 	int flags;
+ {
+ 	const char *stringstart;
+ 	char c, test;
+ 
+ 	for (stringstart = string;;)
+ 		switch (c = FOLDCASE(*pattern++, flags)) {
+ 		case EOS:
+ 			if ((flags & FNM_LEADING_DIR) && *string == '/')
+ 				return (0);
+ 			return (*string == EOS ? 0 : FNM_NOMATCH);
+ 		case '?':
+ 			if (*string == EOS)
+ 				return (FNM_NOMATCH);
+ 			if (*string == '/' && (flags & FNM_PATHNAME))
+ 				return (FNM_NOMATCH);
+ 			if (*string == '.' && (flags & FNM_PERIOD) &&
+ 			    (string == stringstart ||
+ 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ 				return (FNM_NOMATCH);
+ 			++string;
+ 			break;
+ 		case '*':
+ 			c = FOLDCASE(*pattern, flags);
+ 			/* Collapse multiple stars. */
+ 			while (c == '*')
+ 				c = FOLDCASE(*++pattern, flags);
+ 
+ 			if (*string == '.' && (flags & FNM_PERIOD) &&
+ 			    (string == stringstart ||
+ 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ 				return (FNM_NOMATCH);
+ 
+ 			/* Optimize for pattern with * at end or before /. */
+ 			if (c == EOS) {
+ 				if (flags & FNM_PATHNAME)
+ 					return ((flags & FNM_LEADING_DIR) ||
+ 					    strchr(string, '/') == NULL ?
+ 					    0 : FNM_NOMATCH);
+ 				else
+ 					return (0);
+ 			} else if (c == '/' && flags & FNM_PATHNAME) {
+ 				if ((string = strchr(string, '/')) == NULL)
+ 					return (FNM_NOMATCH);
+ 				break;
+ 			}
+ 
+ 			/* General case, use recursion. */
+ 			while ((test = FOLDCASE(*string, flags)) != EOS) {
+ 				if (!fnmatch(pattern, string,
+ 					     flags & ~FNM_PERIOD))
+ 					return (0);
+ 				if (test == '/' && flags & FNM_PATHNAME)
+ 					break;
+ 				++string;
+ 			}
+ 			return (FNM_NOMATCH);
+ 		case '[':
+ 			if (*string == EOS)
+ 				return (FNM_NOMATCH);
+ 			if (*string == '/' && flags & FNM_PATHNAME)
+ 				return (FNM_NOMATCH);
+ 			if ((pattern =
+ 			    rangematch(pattern, FOLDCASE(*string, flags),
+ 				       flags)) == NULL)
+ 				return (FNM_NOMATCH);
+ 			++string;
+ 			break;
+ 		case '\\':
+ 			if (!(flags & FNM_NOESCAPE)) {
+ 				if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
+ 					c = '\\';
+ 					--pattern;
+ 				}
+ 			}
+ 			/* FALLTHROUGH */
+ 		default:
+ 			if (c != FOLDCASE(*string++, flags))
+ 				return (FNM_NOMATCH);
+ 			break;
+ 		}
+ 	/* NOTREACHED */
+ }
+ 
+ static const char *
+ rangematch(pattern, test, flags)
+ 	const char *pattern;
+ 	int test, flags;
+ {
+ 	int negate, ok;
+ 	char c, c2;
+ 
+ 	/*
+ 	 * A bracket expression starting with an unquoted circumflex
+ 	 * character produces unspecified results (IEEE 1003.2-1992,
+ 	 * 3.13.2).  This implementation treats it like '!', for
+ 	 * consistency with the regular expression syntax.
+ 	 * J.T. Conklin (conklin@ngai.kaleida.com)
+ 	 */
+ 	if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
+ 		++pattern;
+ 	
+ 	for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
+ 		if (c == '\\' && !(flags & FNM_NOESCAPE))
+ 			c = FOLDCASE(*pattern++, flags);
+ 		if (c == EOS)
+ 			return (NULL);
+ 		if (*pattern == '-' 
+ 		    && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
+ 		        c2 != ']') {
+ 			pattern += 2;
+ 			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
+ 				c2 = FOLDCASE(*pattern++, flags);
+ 			if (c2 == EOS)
+ 				return (NULL);
+ 			if (c <= test && test <= c2)
+ 				ok = 1;
+ 		} else if (c == test)
+ 			ok = 1;
+ 	}
+ 	return (ok == negate ? NULL : pattern);
+ }
*** a/src/tools/msvc/Mkvcbuild.pm
--- b/src/tools/msvc/Mkvcbuild.pm
***************
*** 43,49 **** sub mkvcbuild
      $solution = new Solution($config);
  
      our @pgportfiles = qw(
!       chklocale.c crypt.c fseeko.c getrusage.c inet_aton.c random.c srandom.c
        unsetenv.c getaddrinfo.c gettimeofday.c kill.c open.c rand.c
        snprintf.c strlcat.c strlcpy.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c
        pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c
--- 43,49 ----
      $solution = new Solution($config);
  
      our @pgportfiles = qw(
!       chklocale.c crypt.c fseeko.c fnmatch.c getrusage.c inet_aton.c random.c srandom.c
        unsetenv.c getaddrinfo.c gettimeofday.c kill.c open.c rand.c
        snprintf.c strlcat.c strlcpy.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c
        pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c
#15Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#14)
Re: Autoconf, libpq and replacement function

Magnus Hagander <magnus@hagander.net> writes:

Or in the same directly, called something else. Like fnmatchstub.h. See
attached, seems reasonable?

Seems okay to me. Note: in future, don't bother posting configure
diffs; nobody wants to look at that, just the changes in the autoconf
input files.

regards, tom lane

#16Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#15)
Re: Autoconf, libpq and replacement function

Tom Lane wrote:

Magnus Hagander <magnus@hagander.net> writes:

Or in the same directly, called something else. Like fnmatchstub.h. See
attached, seems reasonable?

Seems okay to me. Note: in future, don't bother posting configure
diffs; nobody wants to look at that, just the changes in the autoconf
input files.

Ok, will exclude it next time.

FYI, the if check in the configure (and configure.in) was backwards :-)
I posted the patch without testing it to get the "general idea" across.

Will run a set of test of the latest one on msvc as well, and then commit.

//magnus

#17Greg Stark
greg.stark@enterprisedb.com
In reply to: Tom Lane (#15)
Re: Autoconf, libpq and replacement function

If you want people to stop posting configure diffs you should remove
the damn configure file from CVS where it doesn't belong.

greg

On 21 Nov 2008, at 06:49 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Show quoted text

Magnus Hagander <magnus@hagander.net> writes:

Or in the same directly, called something else. Like fnmatchstub.h.
See
attached, seems reasonable?

Seems okay to me. Note: in future, don't bother posting configure
diffs; nobody wants to look at that, just the changes in the autoconf
input files.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#18Tom Lane
tgl@sss.pgh.pa.us
In reply to: Greg Stark (#17)
Re: Autoconf, libpq and replacement function

Greg Stark <greg.stark@enterprisedb.com> writes:

If you want people to stop posting configure diffs you should remove
the damn configure file from CVS where it doesn't belong.

Well, that'd require everyone using CVS to have autoconf installed
--- and not just any autoconf, but the specific version.  Seems like
more pain than it's worth considering most people have little need to
fool with the configure script.

regards, tom lane

#19Bruce Momjian
bruce@momjian.us
In reply to: Tom Lane (#15)
Re: Autoconf, libpq and replacement function

Tom Lane wrote:

Magnus Hagander <magnus@hagander.net> writes:

Or in the same directly, called something else. Like fnmatchstub.h. See
attached, seems reasonable?

Seems okay to me. Note: in future, don't bother posting configure
diffs; nobody wants to look at that, just the changes in the autoconf
input files.

Yea, it makes us ill, especially when it is the first diff in the patch. ;-)

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

#20Peter Eisentraut
peter_e@gmx.net
In reply to: Tom Lane (#9)
Re: Autoconf, libpq and replacement function

Tom Lane wrote:

I'd suggest making the callers do something like

#ifdef HAVE_FNMATCH
#include <fnmatch.h>
#else
#include "port/pg_fnmatch.h"
#endif

The way Autoconf suggests to organize this is to provide a fake
fnmatch.h (they call it fnmatch_.h) and link it to fnmatch.h if it is
needed.

This way, callers don't need to know the difference.

#21Peter Eisentraut
peter_e@gmx.net
In reply to: Tom Lane (#13)
Re: Autoconf, libpq and replacement function

Tom Lane wrote:

Also, right now we have got

src/include/getaddrinfo.h
src/include/getopt_long.h

which really make me itch now that I am contemplating the possibility
that we try to use libc-supplied code for these functions along with
our own header definitions.

These particular header files look like they are robust enough to deal
with this case. But overall this isn't a great idea.

I think the reason we've avoided putting such stuff into include/port/
is that right now that directory consists exclusively of OS-specific
files. Maybe we need another include subdirectory?

I think the idea is rather that you don't need to change call sites to
include the system header or our own. The symlink approach I mentioned
earlier might work.

#22Magnus Hagander
magnus@hagander.net
In reply to: Peter Eisentraut (#21)
Re: Autoconf, libpq and replacement function

Peter Eisentraut wrote:

Tom Lane wrote:

I think the reason we've avoided putting such stuff into include/port/
is that right now that directory consists exclusively of OS-specific
files. Maybe we need another include subdirectory?

I think the idea is rather that you don't need to change call sites to
include the system header or our own. The symlink approach I mentioned
earlier might work.

Anything that needs symlinks will need a set of workarounds on Windows,
having us manually do a copy of the files. We already do this in a
couple of cases, but relying more on it would make things even more
kludgy I think...

//Magnus

#23Peter Eisentraut
peter_e@gmx.net
In reply to: Magnus Hagander (#22)
Re: Autoconf, libpq and replacement function

Magnus Hagander wrote:

Anything that needs symlinks will need a set of workarounds on Windows,
having us manually do a copy of the files. We already do this in a
couple of cases, but relying more on it would make things even more
kludgy I think...

Autoconf automatically uses cp if ln doesn't work. This is already a
solved problem that we currently use in several other situations.

#24Magnus Hagander
magnus@hagander.net
In reply to: Peter Eisentraut (#23)
Re: Autoconf, libpq and replacement function

Peter Eisentraut wrote:

Magnus Hagander wrote:

Anything that needs symlinks will need a set of workarounds on Windows,
having us manually do a copy of the files. We already do this in a
couple of cases, but relying more on it would make things even more
kludgy I think...

Autoconf automatically uses cp if ln doesn't work. This is already a
solved problem that we currently use in several other situations.

I was talking about the MSVC part of the build system.

//Magnus