summaryrefslogtreecommitdiff
path: root/libpq/win32
diff options
context:
space:
mode:
Diffstat (limited to 'libpq/win32')
-rw-r--r--libpq/win32/crypt.c1085
-rw-r--r--libpq/win32/getaddrinfo.c412
-rw-r--r--libpq/win32/inet_aton.c147
-rw-r--r--libpq/win32/libpq.rc.in31
-rw-r--r--libpq/win32/libpqdll.def174
-rw-r--r--libpq/win32/libpqdll.def.orig174
-rw-r--r--libpq/win32/open.c167
-rw-r--r--libpq/win32/pgsleep.c63
-rw-r--r--libpq/win32/pthread-win32.c61
-rw-r--r--libpq/win32/pthread-win32.h22
-rw-r--r--libpq/win32/snprintf.c1141
-rw-r--r--libpq/win32/system.c119
-rw-r--r--libpq/win32/win32.c327
-rw-r--r--libpq/win32/win32.h40
-rw-r--r--libpq/win32/win32error.c206
-rw-r--r--libpq/win32/win32setlocale.c189
16 files changed, 4358 insertions, 0 deletions
diff --git a/libpq/win32/crypt.c b/libpq/win32/crypt.c
new file mode 100644
index 0000000..6a902ef
--- /dev/null
+++ b/libpq/win32/crypt.c
@@ -0,0 +1,1085 @@
+/* src/port/crypt.c */
+/* $NetBSD: crypt.c,v 1.18 2001/03/01 14:37:35 wiz Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tom Truscott.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)crypt.c 8.1.1.1 (Berkeley) 8/18/93";
+#else
+__RCSID("$NetBSD: crypt.c,v 1.18 2001/03/01 14:37:35 wiz Exp $");
+#endif
+#endif /* not lint */
+
+#include "c.h"
+
+#include <limits.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
+static int des_setkey(const char *key);
+static int des_cipher(const char *in, char *out, long salt, int num_iter);
+
+/*
+ * UNIX password, and DES, encryption.
+ * By Tom Truscott, trt@rti.rti.org,
+ * from algorithms by Robert W. Baldwin and James Gillogly.
+ *
+ * References:
+ * "Mathematical Cryptology for Computer Scientists and Mathematicians,"
+ * by Wayne Patterson, 1987, ISBN 0-8476-7438-X.
+ *
+ * "Password Security: A Case History," R. Morris and Ken Thompson,
+ * Communications of the ACM, vol. 22, pp. 594-597, Nov. 1979.
+ *
+ * "DES will be Totally Insecure within Ten Years," M.E. Hellman,
+ * IEEE Spectrum, vol. 16, pp. 32-39, July 1979.
+ */
+
+/* ===== Configuration ==================== */
+
+/*
+ * define "MUST_ALIGN" if your compiler cannot load/store
+ * long integers at arbitrary (e.g. odd) memory locations.
+ * (Either that or never pass unaligned addresses to des_cipher!)
+ */
+/* #define MUST_ALIGN */
+
+#ifdef CHAR_BITS
+#if CHAR_BITS != 8
+#error C_block structure assumes 8 bit characters
+#endif
+#endif
+
+/*
+ * define "B64" to be the declaration for a 64 bit integer.
+ * XXX this feature is currently unused, see "endian" comment below.
+ */
+/* #define B64 int64 */
+
+/*
+ * define "LARGEDATA" to get faster permutations, by using about 72 kilobytes
+ * of lookup tables. This speeds up des_setkey() and des_cipher(), but has
+ * little effect on crypt().
+ */
+/* #define LARGEDATA */
+
+/* compile with "-DSTATIC=void" when profiling */
+#ifndef STATIC
+#define STATIC static void
+#endif
+
+/*
+ * Define the "int32_t" type for integral type with a width of at least
+ * 32 bits.
+ */
+typedef int int32_t;
+
+/* ==================================== */
+
+#define _PASSWORD_EFMT1 '_' /* extended encryption format */
+
+/*
+ * Cipher-block representation (Bob Baldwin):
+ *
+ * DES operates on groups of 64 bits, numbered 1..64 (sigh). One
+ * representation is to store one bit per byte in an array of bytes. Bit N of
+ * the NBS spec is stored as the LSB of the Nth byte (index N-1) in the array.
+ * Another representation stores the 64 bits in 8 bytes, with bits 1..8 in the
+ * first byte, 9..16 in the second, and so on. The DES spec apparently has
+ * bit 1 in the MSB of the first byte, but that is particularly noxious so we
+ * bit-reverse each byte so that bit 1 is the LSB of the first byte, bit 8 is
+ * the MSB of the first byte. Specifically, the 64-bit input data and key are
+ * converted to LSB format, and the output 64-bit block is converted back into
+ * MSB format.
+ *
+ * DES operates internally on groups of 32 bits which are expanded to 48 bits
+ * by permutation E and shrunk back to 32 bits by the S boxes. To speed up
+ * the computation, the expansion is applied only once, the expanded
+ * representation is maintained during the encryption, and a compression
+ * permutation is applied only at the end. To speed up the S-box lookups,
+ * the 48 bits are maintained as eight 6 bit groups, one per byte, which
+ * directly feed the eight S-boxes. Within each byte, the 6 bits are the
+ * most significant ones. The low two bits of each byte are zero. (Thus,
+ * bit 1 of the 48 bit E expansion is stored as the "4"-valued bit of the
+ * first byte in the eight byte representation, bit 2 of the 48 bit value is
+ * the "8"-valued bit, and so on.) In fact, a combined "SPE"-box lookup is
+ * used, in which the output is the 64 bit result of an S-box lookup which
+ * has been permuted by P and expanded by E, and is ready for use in the next
+ * iteration. Two 32-bit wide tables, SPE[0] and SPE[1], are used for this
+ * lookup. Since each byte in the 48 bit path is a multiple of four, indexed
+ * lookup of SPE[0] and SPE[1] is simple and fast. The key schedule and
+ * "salt" are also converted to this 8*(6+2) format. The SPE table size is
+ * 8*64*8 = 4K bytes.
+ *
+ * To speed up bit-parallel operations (such as XOR), the 8 byte
+ * representation is "union"ed with 32 bit values "i0" and "i1", and, on
+ * machines which support it, a 64 bit value "b64". This data structure,
+ * "C_block", has two problems. First, alignment restrictions must be
+ * honored. Second, the byte-order (e.g. little-endian or big-endian) of
+ * the architecture becomes visible.
+ *
+ * The byte-order problem is unfortunate, since on the one hand it is good
+ * to have a machine-independent C_block representation (bits 1..8 in the
+ * first byte, etc.), and on the other hand it is good for the LSB of the
+ * first byte to be the LSB of i0. We cannot have both these things, so we
+ * currently use the "little-endian" representation and avoid any multi-byte
+ * operations that depend on byte order. This largely precludes use of the
+ * 64-bit datatype since the relative order of i0 and i1 are unknown. It
+ * also inhibits grouping the SPE table to look up 12 bits at a time. (The
+ * 12 bits can be stored in a 16-bit field with 3 low-order zeroes and 1
+ * high-order zero, providing fast indexing into a 64-bit wide SPE.) On the
+ * other hand, 64-bit datatypes are currently rare, and a 12-bit SPE lookup
+ * requires a 128 kilobyte table, so perhaps this is not a big loss.
+ *
+ * Permutation representation (Jim Gillogly):
+ *
+ * A transformation is defined by its effect on each of the 8 bytes of the
+ * 64-bit input. For each byte we give a 64-bit output that has the bits in
+ * the input distributed appropriately. The transformation is then the OR
+ * of the 8 sets of 64-bits. This uses 8*256*8 = 16K bytes of storage for
+ * each transformation. Unless LARGEDATA is defined, however, a more compact
+ * table is used which looks up 16 4-bit "chunks" rather than 8 8-bit chunks.
+ * The smaller table uses 16*16*8 = 2K bytes for each transformation. This
+ * is slower but tolerable, particularly for password encryption in which
+ * the SPE transformation is iterated many times. The small tables total 9K
+ * bytes, the large tables total 72K bytes.
+ *
+ * The transformations used are:
+ * IE3264: MSB->LSB conversion, initial permutation, and expansion.
+ * This is done by collecting the 32 even-numbered bits and applying
+ * a 32->64 bit transformation, and then collecting the 32 odd-numbered
+ * bits and applying the same transformation. Since there are only
+ * 32 input bits, the IE3264 transformation table is half the size of
+ * the usual table.
+ * CF6464: Compression, final permutation, and LSB->MSB conversion.
+ * This is done by two trivial 48->32 bit compressions to obtain
+ * a 64-bit block (the bit numbering is given in the "CIFP" table)
+ * followed by a 64->64 bit "cleanup" transformation. (It would
+ * be possible to group the bits in the 64-bit block so that 2
+ * identical 32->32 bit transformations could be used instead,
+ * saving a factor of 4 in space and possibly 2 in time, but
+ * byte-ordering and other complications rear their ugly head.
+ * Similar opportunities/problems arise in the key schedule
+ * transforms.)
+ * PC1ROT: MSB->LSB, PC1 permutation, rotate, and PC2 permutation.
+ * This admittedly baroque 64->64 bit transformation is used to
+ * produce the first code (in 8*(6+2) format) of the key schedule.
+ * PC2ROT[0]: Inverse PC2 permutation, rotate, and PC2 permutation.
+ * It would be possible to define 15 more transformations, each
+ * with a different rotation, to generate the entire key schedule.
+ * To save space, however, we instead permute each code into the
+ * next by using a transformation that "undoes" the PC2 permutation,
+ * rotates the code, and then applies PC2. Unfortunately, PC2
+ * transforms 56 bits into 48 bits, dropping 8 bits, so PC2 is not
+ * invertible. We get around that problem by using a modified PC2
+ * which retains the 8 otherwise-lost bits in the unused low-order
+ * bits of each byte. The low-order bits are cleared when the
+ * codes are stored into the key schedule.
+ * PC2ROT[1]: Same as PC2ROT[0], but with two rotations.
+ * This is faster than applying PC2ROT[0] twice,
+ *
+ * The Bell Labs "salt" (Bob Baldwin):
+ *
+ * The salting is a simple permutation applied to the 48-bit result of E.
+ * Specifically, if bit i (1 <= i <= 24) of the salt is set then bits i and
+ * i+24 of the result are swapped. The salt is thus a 24 bit number, with
+ * 16777216 possible values. (The original salt was 12 bits and could not
+ * swap bits 13..24 with 36..48.)
+ *
+ * It is possible, but ugly, to warp the SPE table to account for the salt
+ * permutation. Fortunately, the conditional bit swapping requires only
+ * about four machine instructions and can be done on-the-fly with about an
+ * 8% performance penalty.
+ */
+
+typedef union
+{
+ unsigned char b[8];
+ struct
+ {
+ int32_t i0;
+ int32_t i1;
+ } b32;
+#if defined(B64)
+ B64 b64;
+#endif
+} C_block;
+
+/*
+ * Convert twenty-four-bit long in host-order
+ * to six bits (and 2 low-order zeroes) per char little-endian format.
+ */
+#define TO_SIX_BIT(rslt, src) { \
+ C_block cvt; \
+ cvt.b[0] = src; src >>= 6; \
+ cvt.b[1] = src; src >>= 6; \
+ cvt.b[2] = src; src >>= 6; \
+ cvt.b[3] = src; \
+ rslt = (cvt.b32.i0 & 0x3f3f3f3fL) << 2; \
+ }
+
+/*
+ * These macros may someday permit efficient use of 64-bit integers.
+ */
+#define ZERO(d,d0,d1) d0 = 0, d1 = 0
+#define LOAD(d,d0,d1,bl) d0 = (bl).b32.i0, d1 = (bl).b32.i1
+#define LOADREG(d,d0,d1,s,s0,s1) d0 = s0, d1 = s1
+#define OR(d,d0,d1,bl) d0 |= (bl).b32.i0, d1 |= (bl).b32.i1
+#define STORE(s,s0,s1,bl) (bl).b32.i0 = s0, (bl).b32.i1 = s1
+#define DCL_BLOCK(d,d0,d1) int32_t d0, d1
+
+#if defined(LARGEDATA)
+ /* Waste memory like crazy. Also, do permutations in line */
+#define LGCHUNKBITS 3
+#define CHUNKBITS (1<<LGCHUNKBITS)
+#define PERM6464(d,d0,d1,cpp,p) \
+ LOAD(d,d0,d1,(p)[(0<<CHUNKBITS)+(cpp)[0]]); \
+ OR (d,d0,d1,(p)[(1<<CHUNKBITS)+(cpp)[1]]); \
+ OR (d,d0,d1,(p)[(2<<CHUNKBITS)+(cpp)[2]]); \
+ OR (d,d0,d1,(p)[(3<<CHUNKBITS)+(cpp)[3]]); \
+ OR (d,d0,d1,(p)[(4<<CHUNKBITS)+(cpp)[4]]); \
+ OR (d,d0,d1,(p)[(5<<CHUNKBITS)+(cpp)[5]]); \
+ OR (d,d0,d1,(p)[(6<<CHUNKBITS)+(cpp)[6]]); \
+ OR (d,d0,d1,(p)[(7<<CHUNKBITS)+(cpp)[7]]);
+#define PERM3264(d,d0,d1,cpp,p) \
+ LOAD(d,d0,d1,(p)[(0<<CHUNKBITS)+(cpp)[0]]); \
+ OR (d,d0,d1,(p)[(1<<CHUNKBITS)+(cpp)[1]]); \
+ OR (d,d0,d1,(p)[(2<<CHUNKBITS)+(cpp)[2]]); \
+ OR (d,d0,d1,(p)[(3<<CHUNKBITS)+(cpp)[3]]);
+#else
+ /* "small data" */
+#define LGCHUNKBITS 2
+#define CHUNKBITS (1<<LGCHUNKBITS)
+#define PERM6464(d,d0,d1,cpp,p) \
+ { C_block tblk; permute(cpp,&tblk,p,8); LOAD (d,d0,d1,tblk); }
+#define PERM3264(d,d0,d1,cpp,p) \
+ { C_block tblk; permute(cpp,&tblk,p,4); LOAD (d,d0,d1,tblk); }
+#endif /* LARGEDATA */
+
+STATIC init_des(void);
+STATIC init_perm(C_block[64 / CHUNKBITS][1 << CHUNKBITS], unsigned char[64], int, int);
+
+#ifndef LARGEDATA
+STATIC permute(unsigned char *, C_block *, C_block *, int);
+#endif
+#ifdef DEBUG
+STATIC prtab(char *, unsigned char *, int);
+#endif
+
+
+#ifndef LARGEDATA
+STATIC
+permute(cp, out, p, chars_in)
+unsigned char *cp;
+C_block *out;
+C_block *p;
+int chars_in;
+{
+ DCL_BLOCK(D, D0, D1);
+ C_block *tp;
+ int t;
+
+ ZERO(D, D0, D1);
+ do
+ {
+ t = *cp++;
+ tp = &p[t & 0xf];
+ OR(D, D0, D1, *tp);
+ p += (1 << CHUNKBITS);
+ tp = &p[t >> 4];
+ OR(D, D0, D1, *tp);
+ p += (1 << CHUNKBITS);
+ } while (--chars_in > 0);
+ STORE(D, D0, D1, *out);
+}
+#endif /* LARGEDATA */
+
+
+/* ===== (mostly) Standard DES Tables ==================== */
+
+static const unsigned char IP[] = { /* initial permutation */
+ 58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7,
+};
+
+/* The final permutation is the inverse of IP - no table is necessary */
+
+static const unsigned char ExpandTr[] = { /* expansion operation */
+ 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1,
+};
+
+static const unsigned char PC1[] = { /* permuted choice table 1 */
+ 57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4,
+};
+
+static const unsigned char Rotates[] = { /* PC1 rotation schedule */
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
+};
+
+/* note: each "row" of PC2 is left-padded with bits that make it invertible */
+static const unsigned char PC2[] = { /* permuted choice table 2 */
+ 9, 18, 14, 17, 11, 24, 1, 5,
+ 22, 25, 3, 28, 15, 6, 21, 10,
+ 35, 38, 23, 19, 12, 4, 26, 8,
+ 43, 54, 16, 7, 27, 20, 13, 2,
+
+ 0, 0, 41, 52, 31, 37, 47, 55,
+ 0, 0, 30, 40, 51, 45, 33, 48,
+ 0, 0, 44, 49, 39, 56, 34, 53,
+ 0, 0, 46, 42, 50, 36, 29, 32,
+};
+
+static const unsigned char S[8][64] = { /* 48->32 bit substitution tables */
+ /* S[1] */
+ {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
+ /* S[2] */
+ {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
+ /* S[3] */
+ {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
+ /* S[4] */
+ {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
+ /* S[5] */
+ {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
+ /* S[6] */
+ {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
+ /* S[7] */
+ {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
+ /* S[8] */
+ {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}
+};
+
+static const unsigned char P32Tr[] = { /* 32-bit permutation function */
+ 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25,
+};
+
+static const unsigned char CIFP[] = { /* compressed/interleaved permutation */
+ 1, 2, 3, 4, 17, 18, 19, 20,
+ 5, 6, 7, 8, 21, 22, 23, 24,
+ 9, 10, 11, 12, 25, 26, 27, 28,
+ 13, 14, 15, 16, 29, 30, 31, 32,
+
+ 33, 34, 35, 36, 49, 50, 51, 52,
+ 37, 38, 39, 40, 53, 54, 55, 56,
+ 41, 42, 43, 44, 57, 58, 59, 60,
+ 45, 46, 47, 48, 61, 62, 63, 64,
+};
+
+static const unsigned char itoa64[] = /* 0..63 => ascii-64 */
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+
+/* ===== Tables that are initialized at run time ==================== */
+
+
+static unsigned char a64toi[128]; /* ascii-64 => 0..63 */
+
+/* Initial key schedule permutation */
+static C_block PC1ROT[64 / CHUNKBITS][1 << CHUNKBITS];
+
+/* Subsequent key schedule rotation permutations */
+static C_block PC2ROT[2][64 / CHUNKBITS][1 << CHUNKBITS];
+
+/* Initial permutation/expansion table */
+static C_block IE3264[32 / CHUNKBITS][1 << CHUNKBITS];
+
+/* Table that combines the S, P, and E operations. */
+static int32_t SPE[2][8][64];
+
+/* compressed/interleaved => final permutation table */
+static C_block CF6464[64 / CHUNKBITS][1 << CHUNKBITS];
+
+
+/* ==================================== */
+
+
+static C_block constdatablock; /* encryption constant */
+static char cryptresult[1 + 4 + 4 + 11 + 1]; /* encrypted result */
+
+extern char *__md5crypt(const char *, const char *); /* XXX */
+extern char *__bcrypt(const char *, const char *); /* XXX */
+
+
+/*
+ * Return a pointer to static data consisting of the "setting"
+ * followed by an encryption produced by the "key" and "setting".
+ */
+char *
+crypt(key, setting)
+const char *key;
+const char *setting;
+{
+ char *encp;
+ int32_t i;
+ int t;
+ int32_t salt;
+ int num_iter,
+ salt_size;
+ C_block keyblock,
+ rsltblock;
+
+#if 0
+ /* Non-DES encryption schemes hook in here. */
+ if (setting[0] == _PASSWORD_NONDES)
+ {
+ switch (setting[1])
+ {
+ case '2':
+ return (__bcrypt(key, setting));
+ case '1':
+ default:
+ return (__md5crypt(key, setting));
+ }
+ }
+#endif
+
+ for (i = 0; i < 8; i++)
+ {
+ if ((t = 2 * (unsigned char) (*key)) != 0)
+ key++;
+ keyblock.b[i] = t;
+ }
+ if (des_setkey((char *) keyblock.b)) /* also initializes "a64toi" */
+ return (NULL);
+
+ encp = &cryptresult[0];
+ switch (*setting)
+ {
+ case _PASSWORD_EFMT1:
+
+ /*
+ * Involve the rest of the password 8 characters at a time.
+ */
+ while (*key)
+ {
+ if (des_cipher((char *) (void *) &keyblock,
+ (char *) (void *) &keyblock, 0L, 1))
+ return (NULL);
+ for (i = 0; i < 8; i++)
+ {
+ if ((t = 2 * (unsigned char) (*key)) != 0)
+ key++;
+ keyblock.b[i] ^= t;
+ }
+ if (des_setkey((char *) keyblock.b))
+ return (NULL);
+ }
+
+ *encp++ = *setting++;
+
+ /* get iteration count */
+ num_iter = 0;
+ for (i = 4; --i >= 0;)
+ {
+ if ((t = (unsigned char) setting[i]) == '\0')
+ t = '.';
+ encp[i] = t;
+ num_iter = (num_iter << 6) | a64toi[t];
+ }
+ setting += 4;
+ encp += 4;
+ salt_size = 4;
+ break;
+ default:
+ num_iter = 25;
+ salt_size = 2;
+ }
+
+ salt = 0;
+ for (i = salt_size; --i >= 0;)
+ {
+ if ((t = (unsigned char) setting[i]) == '\0')
+ t = '.';
+ encp[i] = t;
+ salt = (salt << 6) | a64toi[t];
+ }
+ encp += salt_size;
+ if (des_cipher((char *) (void *) &constdatablock,
+ (char *) (void *) &rsltblock, salt, num_iter))
+ return (NULL);
+
+ /*
+ * Encode the 64 cipher bits as 11 ascii characters.
+ */
+ i = ((int32_t) ((rsltblock.b[0] << 8) | rsltblock.b[1]) << 8) |
+ rsltblock.b[2];
+ encp[3] = itoa64[i & 0x3f];
+ i >>= 6;
+ encp[2] = itoa64[i & 0x3f];
+ i >>= 6;
+ encp[1] = itoa64[i & 0x3f];
+ i >>= 6;
+ encp[0] = itoa64[i];
+ encp += 4;
+ i = ((int32_t) ((rsltblock.b[3] << 8) | rsltblock.b[4]) << 8) |
+ rsltblock.b[5];
+ encp[3] = itoa64[i & 0x3f];
+ i >>= 6;
+ encp[2] = itoa64[i & 0x3f];
+ i >>= 6;
+ encp[1] = itoa64[i & 0x3f];
+ i >>= 6;
+ encp[0] = itoa64[i];
+ encp += 4;
+ i = ((int32_t) ((rsltblock.b[6]) << 8) | rsltblock.b[7]) << 2;
+ encp[2] = itoa64[i & 0x3f];
+ i >>= 6;
+ encp[1] = itoa64[i & 0x3f];
+ i >>= 6;
+ encp[0] = itoa64[i];
+
+ encp[3] = 0;
+
+ return (cryptresult);
+}
+
+
+/*
+ * The Key Schedule, filled in by des_setkey() or setkey().
+ */
+#define KS_SIZE 16
+static C_block KS[KS_SIZE];
+
+static volatile int des_ready = 0;
+
+/*
+ * Set up the key schedule from the key.
+ */
+static int
+des_setkey(key)
+const char *key;
+{
+ DCL_BLOCK(K, K0, K1);
+ C_block *ptabp;
+ int i;
+
+ if (!des_ready)
+ init_des();
+
+ PERM6464(K, K0, K1, (unsigned char *) key, (C_block *) PC1ROT);
+ key = (char *) &KS[0];
+ STORE(K & ~0x03030303L, K0 & ~0x03030303L, K1, *(C_block *) key);
+ for (i = 1; i < 16; i++)
+ {
+ key += sizeof(C_block);
+ STORE(K, K0, K1, *(C_block *) key);
+ ptabp = (C_block *) PC2ROT[Rotates[i] - 1];
+ PERM6464(K, K0, K1, (unsigned char *) key, ptabp);
+ STORE(K & ~0x03030303L, K0 & ~0x03030303L, K1, *(C_block *) key);
+ }
+ return (0);
+}
+
+/*
+ * Encrypt (or decrypt if num_iter < 0) the 8 chars at "in" with abs(num_iter)
+ * iterations of DES, using the given 24-bit salt and the pre-computed key
+ * schedule, and store the resulting 8 chars at "out" (in == out is permitted).
+ *
+ * NOTE: the performance of this routine is critically dependent on your
+ * compiler and machine architecture.
+ */
+static int
+des_cipher(in, out, salt, num_iter)
+const char *in;
+char *out;
+long salt;
+int num_iter;
+{
+ /* variables that we want in registers, most important first */
+#if defined(pdp11)
+ int j;
+#endif
+ int32_t L0,
+ L1,
+ R0,
+ R1,
+ k;
+ C_block *kp;
+ int ks_inc,
+ loop_count;
+ C_block B;
+
+ L0 = salt;
+ TO_SIX_BIT(salt, L0); /* convert to 4*(6+2) format */
+
+#if defined(__vax__) || defined(pdp11)
+ salt = ~salt; /* "x &~ y" is faster than "x & y". */
+#define SALT (~salt)
+#else
+#define SALT salt
+#endif
+
+#if defined(MUST_ALIGN)
+ B.b[0] = in[0];
+ B.b[1] = in[1];
+ B.b[2] = in[2];
+ B.b[3] = in[3];
+ B.b[4] = in[4];
+ B.b[5] = in[5];
+ B.b[6] = in[6];
+ B.b[7] = in[7];
+ LOAD(L, L0, L1, B);
+#else
+ LOAD(L, L0, L1, *(C_block *) in);
+#endif
+ LOADREG(R, R0, R1, L, L0, L1);
+ L0 &= 0x55555555L;
+ L1 &= 0x55555555L;
+ L0 = (L0 << 1) | L1; /* L0 is the even-numbered input bits */
+ R0 &= 0xaaaaaaaaL;
+ R1 = (R1 >> 1) & 0x55555555L;
+ L1 = R0 | R1; /* L1 is the odd-numbered input bits */
+ STORE(L, L0, L1, B);
+ PERM3264(L, L0, L1, B.b, (C_block *) IE3264); /* even bits */
+ PERM3264(R, R0, R1, B.b + 4, (C_block *) IE3264); /* odd bits */
+
+ if (num_iter >= 0)
+ { /* encryption */
+ kp = &KS[0];
+ ks_inc = sizeof(*kp);
+ }
+ else
+ { /* decryption */
+ num_iter = -num_iter;
+ kp = &KS[KS_SIZE - 1];
+ ks_inc = -(long) sizeof(*kp);
+ }
+
+ while (--num_iter >= 0)
+ {
+ loop_count = 8;
+ do
+ {
+
+#define SPTAB(t, i) \
+ (*(int32_t *)((unsigned char *)(t) + (i)*(sizeof(int32_t)/4)))
+#if defined(gould)
+ /* use this if B.b[i] is evaluated just once ... */
+#define DOXOR(x,y,i) x^=SPTAB(SPE[0][i],B.b[i]); y^=SPTAB(SPE[1][i],B.b[i]);
+#else
+#if defined(pdp11)
+ /* use this if your "long" int indexing is slow */
+#define DOXOR(x,y,i) j=B.b[i]; x^=SPTAB(SPE[0][i],j); y^=SPTAB(SPE[1][i],j);
+#else
+ /* use this if "k" is allocated to a register ... */
+#define DOXOR(x,y,i) k=B.b[i]; x^=SPTAB(SPE[0][i],k); y^=SPTAB(SPE[1][i],k);
+#endif
+#endif
+
+#define CRUNCH(p0, p1, q0, q1) \
+ k = ((q0) ^ (q1)) & SALT; \
+ B.b32.i0 = k ^ (q0) ^ kp->b32.i0; \
+ B.b32.i1 = k ^ (q1) ^ kp->b32.i1; \
+ kp = (C_block *)((char *)kp+ks_inc); \
+ \
+ DOXOR(p0, p1, 0); \
+ DOXOR(p0, p1, 1); \
+ DOXOR(p0, p1, 2); \
+ DOXOR(p0, p1, 3); \
+ DOXOR(p0, p1, 4); \
+ DOXOR(p0, p1, 5); \
+ DOXOR(p0, p1, 6); \
+ DOXOR(p0, p1, 7);
+
+ CRUNCH(L0, L1, R0, R1);
+ CRUNCH(R0, R1, L0, L1);
+ } while (--loop_count != 0);
+ kp = (C_block *) ((char *) kp - (ks_inc * KS_SIZE));
+
+
+ /* swap L and R */
+ L0 ^= R0;
+ L1 ^= R1;
+ R0 ^= L0;
+ R1 ^= L1;
+ L0 ^= R0;
+ L1 ^= R1;
+ }
+
+ /* store the encrypted (or decrypted) result */
+ L0 = ((L0 >> 3) & 0x0f0f0f0fL) | ((L1 << 1) & 0xf0f0f0f0L);
+ L1 = ((R0 >> 3) & 0x0f0f0f0fL) | ((R1 << 1) & 0xf0f0f0f0L);
+ STORE(L, L0, L1, B);
+ PERM6464(L, L0, L1, B.b, (C_block *) CF6464);
+#if defined(MUST_ALIGN)
+ STORE(L, L0, L1, B);
+ out[0] = B.b[0];
+ out[1] = B.b[1];
+ out[2] = B.b[2];
+ out[3] = B.b[3];
+ out[4] = B.b[4];
+ out[5] = B.b[5];
+ out[6] = B.b[6];
+ out[7] = B.b[7];
+#else
+ STORE(L, L0, L1, *(C_block *) out);
+#endif
+ return (0);
+}
+
+
+/*
+ * Initialize various tables. This need only be done once. It could even be
+ * done at compile time, if the compiler were capable of that sort of thing.
+ */
+STATIC
+init_des()
+{
+ int i,
+ j;
+ int32_t k;
+ int tableno;
+ static unsigned char perm[64],
+ tmp32[32]; /* "static" for speed */
+
+/* static volatile long init_start = 0; not used */
+
+ /*
+ * table that converts chars "./0-9A-Za-z"to integers 0-63.
+ */
+ for (i = 0; i < 64; i++)
+ a64toi[itoa64[i]] = i;
+
+ /*
+ * PC1ROT - bit reverse, then PC1, then Rotate, then PC2.
+ */
+ for (i = 0; i < 64; i++)
+ perm[i] = 0;
+ for (i = 0; i < 64; i++)
+ {
+ if ((k = PC2[i]) == 0)
+ continue;
+ k += Rotates[0] - 1;
+ if ((k % 28) < Rotates[0])
+ k -= 28;
+ k = PC1[k];
+ if (k > 0)
+ {
+ k--;
+ k = (k | 07) - (k & 07);
+ k++;
+ }
+ perm[i] = k;
+ }
+#ifdef DEBUG
+ prtab("pc1tab", perm, 8);
+#endif
+ init_perm(PC1ROT, perm, 8, 8);
+
+ /*
+ * PC2ROT - PC2 inverse, then Rotate (once or twice), then PC2.
+ */
+ for (j = 0; j < 2; j++)
+ {
+ unsigned char pc2inv[64];
+
+ for (i = 0; i < 64; i++)
+ perm[i] = pc2inv[i] = 0;
+ for (i = 0; i < 64; i++)
+ {
+ if ((k = PC2[i]) == 0)
+ continue;
+ pc2inv[k - 1] = i + 1;
+ }
+ for (i = 0; i < 64; i++)
+ {
+ if ((k = PC2[i]) == 0)
+ continue;
+ k += j;
+ if ((k % 28) <= j)
+ k -= 28;
+ perm[i] = pc2inv[k];
+ }
+#ifdef DEBUG
+ prtab("pc2tab", perm, 8);
+#endif
+ init_perm(PC2ROT[j], perm, 8, 8);
+ }
+
+ /*
+ * Bit reverse, then initial permutation, then expansion.
+ */
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 8; j++)
+ {
+ k = (j < 2) ? 0 : IP[ExpandTr[i * 6 + j - 2] - 1];
+ if (k > 32)
+ k -= 32;
+ else if (k > 0)
+ k--;
+ if (k > 0)
+ {
+ k--;
+ k = (k | 07) - (k & 07);
+ k++;
+ }
+ perm[i * 8 + j] = k;
+ }
+ }
+#ifdef DEBUG
+ prtab("ietab", perm, 8);
+#endif
+ init_perm(IE3264, perm, 4, 8);
+
+ /*
+ * Compression, then final permutation, then bit reverse.
+ */
+ for (i = 0; i < 64; i++)
+ {
+ k = IP[CIFP[i] - 1];
+ if (k > 0)
+ {
+ k--;
+ k = (k | 07) - (k & 07);
+ k++;
+ }
+ perm[k - 1] = i + 1;
+ }
+#ifdef DEBUG
+ prtab("cftab", perm, 8);
+#endif
+ init_perm(CF6464, perm, 8, 8);
+
+ /*
+ * SPE table
+ */
+ for (i = 0; i < 48; i++)
+ perm[i] = P32Tr[ExpandTr[i] - 1];
+ for (tableno = 0; tableno < 8; tableno++)
+ {
+ for (j = 0; j < 64; j++)
+ {
+ k = (((j >> 0) & 01) << 5) |
+ (((j >> 1) & 01) << 3) |
+ (((j >> 2) & 01) << 2) |
+ (((j >> 3) & 01) << 1) |
+ (((j >> 4) & 01) << 0) |
+ (((j >> 5) & 01) << 4);
+ k = S[tableno][k];
+ k = (((k >> 3) & 01) << 0) |
+ (((k >> 2) & 01) << 1) |
+ (((k >> 1) & 01) << 2) |
+ (((k >> 0) & 01) << 3);
+ for (i = 0; i < 32; i++)
+ tmp32[i] = 0;
+ for (i = 0; i < 4; i++)
+ tmp32[4 * tableno + i] = (k >> i) & 01;
+ k = 0;
+ for (i = 24; --i >= 0;)
+ k = (k << 1) | tmp32[perm[i] - 1];
+ TO_SIX_BIT(SPE[0][tableno][j], k);
+ k = 0;
+ for (i = 24; --i >= 0;)
+ k = (k << 1) | tmp32[perm[i + 24] - 1];
+ TO_SIX_BIT(SPE[1][tableno][j], k);
+ }
+ }
+
+ des_ready = 1;
+}
+
+/*
+ * Initialize "perm" to represent transformation "p", which rearranges
+ * (perhaps with expansion and/or contraction) one packed array of bits
+ * (of size "chars_in" characters) into another array (of size "chars_out"
+ * characters).
+ *
+ * "perm" must be all-zeroes on entry to this routine.
+ */
+STATIC
+init_perm(perm, p, chars_in, chars_out)
+C_block perm[64 / CHUNKBITS][1 << CHUNKBITS];
+unsigned char p[64];
+int chars_in,
+ chars_out;
+{
+ int i,
+ j,
+ k,
+ l;
+
+ for (k = 0; k < chars_out * 8; k++)
+ { /* each output bit position */
+ l = p[k] - 1; /* where this bit comes from */
+ if (l < 0)
+ continue; /* output bit is always 0 */
+ i = l >> LGCHUNKBITS; /* which chunk this bit comes from */
+ l = 1 << (l & (CHUNKBITS - 1)); /* mask for this bit */
+ for (j = 0; j < (1 << CHUNKBITS); j++)
+ { /* each chunk value */
+ if ((j & l) != 0)
+ perm[i][j].b[k >> 3] |= 1 << (k & 07);
+ }
+ }
+}
+
+/*
+ * "setkey" routine (for backwards compatibility)
+ */
+#ifdef NOT_USED
+int
+setkey(key)
+const char *key;
+{
+ int i,
+ j,
+ k;
+ C_block keyblock;
+
+ for (i = 0; i < 8; i++)
+ {
+ k = 0;
+ for (j = 0; j < 8; j++)
+ {
+ k <<= 1;
+ k |= (unsigned char) *key++;
+ }
+ keyblock.b[i] = k;
+ }
+ return (des_setkey((char *) keyblock.b));
+}
+
+/*
+ * "encrypt" routine (for backwards compatibility)
+ */
+static int
+encrypt(block, flag)
+char *block;
+int flag;
+{
+ int i,
+ j,
+ k;
+ C_block cblock;
+
+ for (i = 0; i < 8; i++)
+ {
+ k = 0;
+ for (j = 0; j < 8; j++)
+ {
+ k <<= 1;
+ k |= (unsigned char) *block++;
+ }
+ cblock.b[i] = k;
+ }
+ if (des_cipher((char *) &cblock, (char *) &cblock, 0L, (flag ? -1 : 1)))
+ return (1);
+ for (i = 7; i >= 0; i--)
+ {
+ k = cblock.b[i];
+ for (j = 7; j >= 0; j--)
+ {
+ *--block = k & 01;
+ k >>= 1;
+ }
+ }
+ return (0);
+}
+#endif
+
+#ifdef DEBUG
+STATIC
+prtab(s, t, num_rows)
+char *s;
+unsigned char *t;
+int num_rows;
+{
+ int i,
+ j;
+
+ (void) printf("%s:\n", s);
+ for (i = 0; i < num_rows; i++)
+ {
+ for (j = 0; j < 8; j++)
+ (void) printf("%3d", t[i * 8 + j]);
+ (void) printf("\n");
+ }
+ (void) printf("\n");
+}
+
+#endif
diff --git a/libpq/win32/getaddrinfo.c b/libpq/win32/getaddrinfo.c
new file mode 100644
index 0000000..90c1b87
--- /dev/null
+++ b/libpq/win32/getaddrinfo.c
@@ -0,0 +1,412 @@
+/*-------------------------------------------------------------------------
+ *
+ * getaddrinfo.c
+ * Support getaddrinfo() on platforms that don't have it.
+ *
+ * We also supply getnameinfo() here, assuming that the platform will have
+ * it if and only if it has getaddrinfo(). If this proves false on some
+ * platform, we'll need to split this file and provide a separate configure
+ * test for getnameinfo().
+ *
+ * Windows may or may not have these routines, so we handle Windows specially
+ * by dynamically checking for their existence. If they already exist, we
+ * use the Windows native routines, but if not, we use our own.
+ *
+ *
+ * Copyright (c) 2003-2016, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/getaddrinfo.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/* This is intended to be used in both frontend and backend, so use c.h */
+#include "c.h"
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "getaddrinfo.h"
+#include "libpq/pqcomm.h" /* needed for struct sockaddr_storage */
+
+
+#ifdef WIN32
+/*
+ * The native routines may or may not exist on the Windows platform we are on,
+ * so we dynamically look up the routines, and call them via function pointers.
+ * Here we need to declare what the function pointers look like
+ */
+typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename,
+ const char *servname,
+ const struct addrinfo * hints,
+ struct addrinfo ** res);
+
+typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo * ai);
+
+typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr * sa,
+ int salen,
+ char *host, int hostlen,
+ char *serv, int servlen,
+ int flags);
+
+/* static pointers to the native routines, so we only do the lookup once. */
+static getaddrinfo_ptr_t getaddrinfo_ptr = NULL;
+static freeaddrinfo_ptr_t freeaddrinfo_ptr = NULL;
+static getnameinfo_ptr_t getnameinfo_ptr = NULL;
+
+
+static bool
+haveNativeWindowsIPv6routines(void)
+{
+ void *hLibrary = NULL;
+ static bool alreadyLookedForIpv6routines = false;
+
+ if (alreadyLookedForIpv6routines)
+ return (getaddrinfo_ptr != NULL);
+
+ /*
+ * For Windows XP and Windows 2003 (and longhorn/vista), the IPv6 routines
+ * are present in the WinSock 2 library (ws2_32.dll). Try that first
+ */
+
+ hLibrary = LoadLibraryA("ws2_32");
+
+ if (hLibrary == NULL || GetProcAddress(hLibrary, "getaddrinfo") == NULL)
+ {
+ /*
+ * Well, ws2_32 doesn't exist, or more likely doesn't have
+ * getaddrinfo.
+ */
+ if (hLibrary != NULL)
+ FreeLibrary(hLibrary);
+
+ /*
+ * In Windows 2000, there was only the IPv6 Technology Preview look in
+ * the IPv6 WinSock library (wship6.dll).
+ */
+
+ hLibrary = LoadLibraryA("wship6");
+ }
+
+ /* If hLibrary is null, we couldn't find a dll with functions */
+ if (hLibrary != NULL)
+ {
+ /* We found a dll, so now get the addresses of the routines */
+
+ getaddrinfo_ptr = (getaddrinfo_ptr_t) GetProcAddress(hLibrary,
+ "getaddrinfo");
+ freeaddrinfo_ptr = (freeaddrinfo_ptr_t) GetProcAddress(hLibrary,
+ "freeaddrinfo");
+ getnameinfo_ptr = (getnameinfo_ptr_t) GetProcAddress(hLibrary,
+ "getnameinfo");
+
+ /*
+ * If any one of the routines is missing, let's play it safe and
+ * ignore them all
+ */
+ if (getaddrinfo_ptr == NULL ||
+ freeaddrinfo_ptr == NULL ||
+ getnameinfo_ptr == NULL)
+ {
+ FreeLibrary(hLibrary);
+ hLibrary = NULL;
+ getaddrinfo_ptr = NULL;
+ freeaddrinfo_ptr = NULL;
+ getnameinfo_ptr = NULL;
+ }
+ }
+
+ alreadyLookedForIpv6routines = true;
+ return (getaddrinfo_ptr != NULL);
+}
+#endif
+
+
+/*
+ * get address info for ipv4 sockets.
+ *
+ * Bugs: - only one addrinfo is set even though hintp is NULL or
+ * ai_socktype is 0
+ * - AI_CANONNAME is not supported.
+ * - servname can only be a number, not text.
+ */
+int
+getaddrinfo(const char *node, const char *service,
+ const struct addrinfo * hintp,
+ struct addrinfo ** res)
+{
+ struct addrinfo *ai;
+ struct sockaddr_in sin,
+ *psin;
+ struct addrinfo hints;
+
+#ifdef WIN32
+
+ /*
+ * If Windows has native IPv6 support, use the native Windows routine.
+ * Otherwise, fall through and use our own code.
+ */
+ if (haveNativeWindowsIPv6routines())
+ return (*getaddrinfo_ptr) (node, service, hintp, res);
+#endif
+
+ if (hintp == NULL)
+ {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ }
+ else
+ memcpy(&hints, hintp, sizeof(hints));
+
+ if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
+ return EAI_FAMILY;
+
+ if (hints.ai_socktype == 0)
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (!node && !service)
+ return EAI_NONAME;
+
+ memset(&sin, 0, sizeof(sin));
+
+ sin.sin_family = AF_INET;
+
+ if (node)
+ {
+ if (node[0] == '\0')
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ else if (hints.ai_flags & AI_NUMERICHOST)
+ {
+ if (!inet_aton(node, &sin.sin_addr))
+ return EAI_NONAME;
+ }
+ else
+ {
+ struct hostent *hp;
+
+#ifdef FRONTEND
+ struct hostent hpstr;
+ char buf[BUFSIZ];
+ int herrno = 0;
+
+ pqGethostbyname(node, &hpstr, buf, sizeof(buf),
+ &hp, &herrno);
+#else
+ hp = gethostbyname(node);
+#endif
+ if (hp == NULL)
+ {
+ switch (h_errno)
+ {
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ return EAI_NONAME;
+ case TRY_AGAIN:
+ return EAI_AGAIN;
+ case NO_RECOVERY:
+ default:
+ return EAI_FAIL;
+ }
+ }
+ if (hp->h_addrtype != AF_INET)
+ return EAI_FAIL;
+
+ memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
+ }
+ }
+ else
+ {
+ if (hints.ai_flags & AI_PASSIVE)
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ else
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ }
+
+ if (service)
+ sin.sin_port = htons((unsigned short) atoi(service));
+
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
+ sin.sin_len = sizeof(sin);
+#endif
+
+ ai = malloc(sizeof(*ai));
+ if (!ai)
+ return EAI_MEMORY;
+
+ psin = malloc(sizeof(*psin));
+ if (!psin)
+ {
+ free(ai);
+ return EAI_MEMORY;
+ }
+
+ memcpy(psin, &sin, sizeof(*psin));
+
+ ai->ai_flags = 0;
+ ai->ai_family = AF_INET;
+ ai->ai_socktype = hints.ai_socktype;
+ ai->ai_protocol = hints.ai_protocol;
+ ai->ai_addrlen = sizeof(*psin);
+ ai->ai_addr = (struct sockaddr *) psin;
+ ai->ai_canonname = NULL;
+ ai->ai_next = NULL;
+
+ *res = ai;
+
+ return 0;
+}
+
+
+void
+freeaddrinfo(struct addrinfo * res)
+{
+ if (res)
+ {
+#ifdef WIN32
+
+ /*
+ * If Windows has native IPv6 support, use the native Windows routine.
+ * Otherwise, fall through and use our own code.
+ */
+ if (haveNativeWindowsIPv6routines())
+ {
+ (*freeaddrinfo_ptr) (res);
+ return;
+ }
+#endif
+
+ if (res->ai_addr)
+ free(res->ai_addr);
+ free(res);
+ }
+}
+
+
+const char *
+gai_strerror(int errcode)
+{
+#ifdef HAVE_HSTRERROR
+ int hcode;
+
+ switch (errcode)
+ {
+ case EAI_NONAME:
+ hcode = HOST_NOT_FOUND;
+ break;
+ case EAI_AGAIN:
+ hcode = TRY_AGAIN;
+ break;
+ case EAI_FAIL:
+ default:
+ hcode = NO_RECOVERY;
+ break;
+ }
+
+ return hstrerror(hcode);
+#else /* !HAVE_HSTRERROR */
+
+ switch (errcode)
+ {
+ case EAI_NONAME:
+ return "Unknown host";
+ case EAI_AGAIN:
+ return "Host name lookup failure";
+ /* Errors below are probably WIN32 only */
+#ifdef EAI_BADFLAGS
+ case EAI_BADFLAGS:
+ return "Invalid argument";
+#endif
+#ifdef EAI_FAMILY
+ case EAI_FAMILY:
+ return "Address family not supported";
+#endif
+#ifdef EAI_MEMORY
+ case EAI_MEMORY:
+ return "Not enough memory";
+#endif
+#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME /* MSVC/WIN64 duplicate */
+ case EAI_NODATA:
+ return "No host data of that type was found";
+#endif
+#ifdef EAI_SERVICE
+ case EAI_SERVICE:
+ return "Class type not found";
+#endif
+#ifdef EAI_SOCKTYPE
+ case EAI_SOCKTYPE:
+ return "Socket type not supported";
+#endif
+ default:
+ return "Unknown server error";
+ }
+#endif /* HAVE_HSTRERROR */
+}
+
+/*
+ * Convert an ipv4 address to a hostname.
+ *
+ * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV behavior.
+ * It will never resolve a hostname.
+ * - No IPv6 support.
+ */
+int
+getnameinfo(const struct sockaddr * sa, int salen,
+ char *node, int nodelen,
+ char *service, int servicelen, int flags)
+{
+#ifdef WIN32
+
+ /*
+ * If Windows has native IPv6 support, use the native Windows routine.
+ * Otherwise, fall through and use our own code.
+ */
+ if (haveNativeWindowsIPv6routines())
+ return (*getnameinfo_ptr) (sa, salen, node, nodelen,
+ service, servicelen, flags);
+#endif
+
+ /* Invalid arguments. */
+ if (sa == NULL || (node == NULL && service == NULL))
+ return EAI_FAIL;
+
+#ifdef HAVE_IPV6
+ if (sa->sa_family == AF_INET6)
+ return EAI_FAMILY;
+#endif
+
+ /* Unsupported flags. */
+ if (flags & NI_NAMEREQD)
+ return EAI_AGAIN;
+
+ if (node)
+ {
+ if (sa->sa_family == AF_INET)
+ {
+ if (inet_net_ntop(AF_INET, &((struct sockaddr_in *) sa)->sin_addr,
+ sa->sa_family == AF_INET ? 32 : 128,
+ node, nodelen) == NULL)
+ return EAI_MEMORY;
+ }
+ else
+ return EAI_MEMORY;
+ }
+
+ if (service)
+ {
+ int ret = -1;
+
+ if (sa->sa_family == AF_INET)
+ {
+ ret = snprintf(service, servicelen, "%d",
+ ntohs(((struct sockaddr_in *) sa)->sin_port));
+ }
+ if (ret == -1 || ret >= servicelen)
+ return EAI_MEMORY;
+ }
+
+ return 0;
+}
diff --git a/libpq/win32/inet_aton.c b/libpq/win32/inet_aton.c
new file mode 100644
index 0000000..27e8aaa
--- /dev/null
+++ b/libpq/win32/inet_aton.c
@@ -0,0 +1,147 @@
+/* src/port/inet_aton.c
+ *
+ * This inet_aton() function was taken from the GNU C library and
+ * incorporated into Postgres for those systems which do not have this
+ * routine in their standard C libraries.
+ *
+ * The function was been extracted whole from the file inet_aton.c in
+ * Release 5.3.12 of the Linux C library, which is derived from the
+ * GNU C library, by Bryan Henderson in October 1996. The copyright
+ * notice from that file is below.
+ */
+
+/*
+ * Copyright (c) 1983, 1990, 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.
+ * 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. */
+
+#include "c.h"
+
+#include <netinet/in.h>
+#include <ctype.h>
+
+/*
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+inet_aton(const char *cp, struct in_addr * addr)
+{
+ unsigned int val;
+ int base,
+ n;
+ char c;
+ u_int parts[4];
+ u_int *pp = parts;
+
+ for (;;)
+ {
+ /*
+ * Collect number up to ``.''. Values are specified as for C: 0x=hex,
+ * 0=octal, other=decimal.
+ */
+ val = 0;
+ base = 10;
+ if (*cp == '0')
+ {
+ if (*++cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ else
+ base = 8;
+ }
+ while ((c = *cp) != '\0')
+ {
+ if (isdigit((unsigned char) c))
+ {
+ val = (val * base) + (c - '0');
+ cp++;
+ continue;
+ }
+ if (base == 16 && isxdigit((unsigned char) c))
+ {
+ val = (val << 4) +
+ (c + 10 - (islower((unsigned char) c) ? 'a' : 'A'));
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (*cp == '.')
+ {
+ /*
+ * Internet format: a.b.c.d a.b.c (with c treated as 16-bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xff)
+ return 0;
+ *pp++ = val, cp++;
+ }
+ else
+ break;
+ }
+
+ /*
+ * Check for trailing junk.
+ */
+ while (*cp)
+ if (!isspace((unsigned char) *cp++))
+ return 0;
+
+ /*
+ * Concoct the address according to the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n)
+ {
+
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return 0;
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return 0;
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return 0;
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr)
+ addr->s_addr = htonl(val);
+ return 1;
+}
diff --git a/libpq/win32/libpq.rc.in b/libpq/win32/libpq.rc.in
new file mode 100644
index 0000000..da97574
--- /dev/null
+++ b/libpq/win32/libpq.rc.in
@@ -0,0 +1,31 @@
+#include <winver.h>
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 9,6,5,0
+ PRODUCTVERSION 9,6,5,0
+ FILEFLAGSMASK 0x3fL
+ FILEFLAGS 0
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0"
+ BEGIN
+ VALUE "CompanyName", "\0"
+ VALUE "FileDescription", "PostgreSQL Access Library\0"
+ VALUE "FileVersion", "9.6.5\0"
+ VALUE "InternalName", "libpq\0"
+ VALUE "LegalCopyright", "Copyright (C) 2016\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "libpq.dll\0"
+ VALUE "ProductName", "PostgreSQL\0"
+ VALUE "ProductVersion", "9.6.5\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/libpq/win32/libpqdll.def b/libpq/win32/libpqdll.def
new file mode 100644
index 0000000..810d4be
--- /dev/null
+++ b/libpq/win32/libpqdll.def
@@ -0,0 +1,174 @@
+; DEF file for win32.mak release build and for Makefile.shlib (MinGW)
+; LIBRARY LIBPQ.dll
+EXPORTS
+ PQconnectdb @ 1
+ PQsetdbLogin @ 2
+ PQconndefaults @ 3
+ PQfinish @ 4
+ PQreset @ 5
+ PQrequestCancel @ 6
+ PQdb @ 7
+ PQuser @ 8
+ PQpass @ 9
+ PQhost @ 10
+ PQport @ 11
+ PQtty @ 12
+ PQoptions @ 13
+ PQstatus @ 14
+ PQerrorMessage @ 15
+ PQsocket @ 16
+ PQbackendPID @ 17
+ PQtrace @ 18
+ PQuntrace @ 19
+ PQsetNoticeProcessor @ 20
+ PQexec @ 21
+ PQnotifies @ 22
+ PQsendQuery @ 23
+ PQgetResult @ 24
+ PQisBusy @ 25
+ PQconsumeInput @ 26
+ PQgetline @ 27
+ PQputline @ 28
+ PQgetlineAsync @ 29
+ PQputnbytes @ 30
+ PQendcopy @ 31
+ PQfn @ 32
+ PQresultStatus @ 33
+ PQntuples @ 34
+ PQnfields @ 35
+ PQbinaryTuples @ 36
+ PQfname @ 37
+ PQfnumber @ 38
+ PQftype @ 39
+ PQfsize @ 40
+ PQfmod @ 41
+ PQcmdStatus @ 42
+ PQoidStatus @ 43
+ PQcmdTuples @ 44
+ PQgetvalue @ 45
+ PQgetlength @ 46
+ PQgetisnull @ 47
+ PQclear @ 48
+ PQmakeEmptyPGresult @ 49
+ PQprint @ 50
+ PQdisplayTuples @ 51
+ PQprintTuples @ 52
+ lo_open @ 53
+ lo_close @ 54
+ lo_read @ 55
+ lo_write @ 56
+ lo_lseek @ 57
+ lo_creat @ 58
+ lo_tell @ 59
+ lo_unlink @ 60
+ lo_import @ 61
+ lo_export @ 62
+ pgresStatus @ 63
+ PQmblen @ 64
+ PQresultErrorMessage @ 65
+ PQresStatus @ 66
+ termPQExpBuffer @ 67
+ appendPQExpBufferChar @ 68
+ initPQExpBuffer @ 69
+ resetPQExpBuffer @ 70
+ PQoidValue @ 71
+ PQclientEncoding @ 72
+ PQenv2encoding @ 73
+ appendBinaryPQExpBuffer @ 74
+ appendPQExpBufferStr @ 75
+ destroyPQExpBuffer @ 76
+ createPQExpBuffer @ 77
+ PQconninfoFree @ 78
+ PQconnectPoll @ 79
+ PQconnectStart @ 80
+ PQflush @ 81
+ PQisnonblocking @ 82
+ PQresetPoll @ 83
+ PQresetStart @ 84
+ PQsetClientEncoding @ 85
+ PQsetnonblocking @ 86
+ PQfreeNotify @ 87
+ PQescapeString @ 88
+ PQescapeBytea @ 89
+ printfPQExpBuffer @ 90
+ appendPQExpBuffer @ 91
+ pg_encoding_to_char @ 92
+ pg_utf_mblen @ 93
+ PQunescapeBytea @ 94
+ PQfreemem @ 95
+ PQtransactionStatus @ 96
+ PQparameterStatus @ 97
+ PQprotocolVersion @ 98
+ PQsetErrorVerbosity @ 99
+ PQsetNoticeReceiver @ 100
+ PQexecParams @ 101
+ PQsendQueryParams @ 102
+ PQputCopyData @ 103
+ PQputCopyEnd @ 104
+ PQgetCopyData @ 105
+ PQresultErrorField @ 106
+ PQftable @ 107
+ PQftablecol @ 108
+ PQfformat @ 109
+ PQexecPrepared @ 110
+ PQsendQueryPrepared @ 111
+ PQdsplen @ 112
+ PQserverVersion @ 113
+ PQgetssl @ 114
+ pg_char_to_encoding @ 115
+ pg_valid_server_encoding @ 116
+ pqsignal @ 117
+ PQprepare @ 118
+ PQsendPrepare @ 119
+ PQgetCancel @ 120
+ PQfreeCancel @ 121
+ PQcancel @ 122
+ lo_create @ 123
+ PQinitSSL @ 124
+ PQregisterThreadLock @ 125
+ PQescapeStringConn @ 126
+ PQescapeByteaConn @ 127
+ PQencryptPassword @ 128
+ PQisthreadsafe @ 129
+ enlargePQExpBuffer @ 130
+ PQnparams @ 131
+ PQparamtype @ 132
+ PQdescribePrepared @ 133
+ PQdescribePortal @ 134
+ PQsendDescribePrepared @ 135
+ PQsendDescribePortal @ 136
+ lo_truncate @ 137
+ PQconnectionUsedPassword @ 138
+ pg_valid_server_encoding_id @ 139
+ PQconnectionNeedsPassword @ 140
+ lo_import_with_oid @ 141
+ PQcopyResult @ 142
+ PQsetResultAttrs @ 143
+ PQsetvalue @ 144
+ PQresultAlloc @ 145
+ PQregisterEventProc @ 146
+ PQinstanceData @ 147
+ PQsetInstanceData @ 148
+ PQresultInstanceData @ 149
+ PQresultSetInstanceData @ 150
+ PQfireResultCreateEvents @ 151
+ PQconninfoParse @ 152
+ PQinitOpenSSL @ 153
+ PQescapeLiteral @ 154
+ PQescapeIdentifier @ 155
+ PQconnectdbParams @ 156
+ PQconnectStartParams @ 157
+ PQping @ 158
+ PQpingParams @ 159
+ PQlibVersion @ 160
+ PQsetSingleRowMode @ 161
+ lo_lseek64 @ 162
+ lo_tell64 @ 163
+ lo_truncate64 @ 164
+ PQconninfo @ 165
+ PQsslInUse @ 166
+ PQsslStruct @ 167
+ PQsslAttributeNames @ 168
+ PQsslAttribute @ 169
+ PQsetErrorContextVisibility @ 170
+ PQresultVerboseErrorMessage @ 171
diff --git a/libpq/win32/libpqdll.def.orig b/libpq/win32/libpqdll.def.orig
new file mode 100644
index 0000000..0c9e8e4
--- /dev/null
+++ b/libpq/win32/libpqdll.def.orig
@@ -0,0 +1,174 @@
+; DEF file for win32.mak release build and for Makefile.shlib (MinGW)
+LIBRARY LIBPQ.dll
+EXPORTS
+ PQconnectdb @ 1
+ PQsetdbLogin @ 2
+ PQconndefaults @ 3
+ PQfinish @ 4
+ PQreset @ 5
+ PQrequestCancel @ 6
+ PQdb @ 7
+ PQuser @ 8
+ PQpass @ 9
+ PQhost @ 10
+ PQport @ 11
+ PQtty @ 12
+ PQoptions @ 13
+ PQstatus @ 14
+ PQerrorMessage @ 15
+ PQsocket @ 16
+ PQbackendPID @ 17
+ PQtrace @ 18
+ PQuntrace @ 19
+ PQsetNoticeProcessor @ 20
+ PQexec @ 21
+ PQnotifies @ 22
+ PQsendQuery @ 23
+ PQgetResult @ 24
+ PQisBusy @ 25
+ PQconsumeInput @ 26
+ PQgetline @ 27
+ PQputline @ 28
+ PQgetlineAsync @ 29
+ PQputnbytes @ 30
+ PQendcopy @ 31
+ PQfn @ 32
+ PQresultStatus @ 33
+ PQntuples @ 34
+ PQnfields @ 35
+ PQbinaryTuples @ 36
+ PQfname @ 37
+ PQfnumber @ 38
+ PQftype @ 39
+ PQfsize @ 40
+ PQfmod @ 41
+ PQcmdStatus @ 42
+ PQoidStatus @ 43
+ PQcmdTuples @ 44
+ PQgetvalue @ 45
+ PQgetlength @ 46
+ PQgetisnull @ 47
+ PQclear @ 48
+ PQmakeEmptyPGresult @ 49
+ PQprint @ 50
+ PQdisplayTuples @ 51
+ PQprintTuples @ 52
+ lo_open @ 53
+ lo_close @ 54
+ lo_read @ 55
+ lo_write @ 56
+ lo_lseek @ 57
+ lo_creat @ 58
+ lo_tell @ 59
+ lo_unlink @ 60
+ lo_import @ 61
+ lo_export @ 62
+ pgresStatus @ 63
+ PQmblen @ 64
+ PQresultErrorMessage @ 65
+ PQresStatus @ 66
+ termPQExpBuffer @ 67
+ appendPQExpBufferChar @ 68
+ initPQExpBuffer @ 69
+ resetPQExpBuffer @ 70
+ PQoidValue @ 71
+ PQclientEncoding @ 72
+ PQenv2encoding @ 73
+ appendBinaryPQExpBuffer @ 74
+ appendPQExpBufferStr @ 75
+ destroyPQExpBuffer @ 76
+ createPQExpBuffer @ 77
+ PQconninfoFree @ 78
+ PQconnectPoll @ 79
+ PQconnectStart @ 80
+ PQflush @ 81
+ PQisnonblocking @ 82
+ PQresetPoll @ 83
+ PQresetStart @ 84
+ PQsetClientEncoding @ 85
+ PQsetnonblocking @ 86
+ PQfreeNotify @ 87
+ PQescapeString @ 88
+ PQescapeBytea @ 89
+ printfPQExpBuffer @ 90
+ appendPQExpBuffer @ 91
+ pg_encoding_to_char @ 92
+ pg_utf_mblen @ 93
+ PQunescapeBytea @ 94
+ PQfreemem @ 95
+ PQtransactionStatus @ 96
+ PQparameterStatus @ 97
+ PQprotocolVersion @ 98
+ PQsetErrorVerbosity @ 99
+ PQsetNoticeReceiver @ 100
+ PQexecParams @ 101
+ PQsendQueryParams @ 102
+ PQputCopyData @ 103
+ PQputCopyEnd @ 104
+ PQgetCopyData @ 105
+ PQresultErrorField @ 106
+ PQftable @ 107
+ PQftablecol @ 108
+ PQfformat @ 109
+ PQexecPrepared @ 110
+ PQsendQueryPrepared @ 111
+ PQdsplen @ 112
+ PQserverVersion @ 113
+ PQgetssl @ 114
+ pg_char_to_encoding @ 115
+ pg_valid_server_encoding @ 116
+ pqsignal @ 117
+ PQprepare @ 118
+ PQsendPrepare @ 119
+ PQgetCancel @ 120
+ PQfreeCancel @ 121
+ PQcancel @ 122
+ lo_create @ 123
+ PQinitSSL @ 124
+ PQregisterThreadLock @ 125
+ PQescapeStringConn @ 126
+ PQescapeByteaConn @ 127
+ PQencryptPassword @ 128
+ PQisthreadsafe @ 129
+ enlargePQExpBuffer @ 130
+ PQnparams @ 131
+ PQparamtype @ 132
+ PQdescribePrepared @ 133
+ PQdescribePortal @ 134
+ PQsendDescribePrepared @ 135
+ PQsendDescribePortal @ 136
+ lo_truncate @ 137
+ PQconnectionUsedPassword @ 138
+ pg_valid_server_encoding_id @ 139
+ PQconnectionNeedsPassword @ 140
+ lo_import_with_oid @ 141
+ PQcopyResult @ 142
+ PQsetResultAttrs @ 143
+ PQsetvalue @ 144
+ PQresultAlloc @ 145
+ PQregisterEventProc @ 146
+ PQinstanceData @ 147
+ PQsetInstanceData @ 148
+ PQresultInstanceData @ 149
+ PQresultSetInstanceData @ 150
+ PQfireResultCreateEvents @ 151
+ PQconninfoParse @ 152
+ PQinitOpenSSL @ 153
+ PQescapeLiteral @ 154
+ PQescapeIdentifier @ 155
+ PQconnectdbParams @ 156
+ PQconnectStartParams @ 157
+ PQping @ 158
+ PQpingParams @ 159
+ PQlibVersion @ 160
+ PQsetSingleRowMode @ 161
+ lo_lseek64 @ 162
+ lo_tell64 @ 163
+ lo_truncate64 @ 164
+ PQconninfo @ 165
+ PQsslInUse @ 166
+ PQsslStruct @ 167
+ PQsslAttributeNames @ 168
+ PQsslAttribute @ 169
+ PQsetErrorContextVisibility @ 170
+ PQresultVerboseErrorMessage @ 171
diff --git a/libpq/win32/open.c b/libpq/win32/open.c
new file mode 100644
index 0000000..717375d
--- /dev/null
+++ b/libpq/win32/open.c
@@ -0,0 +1,167 @@
+/*-------------------------------------------------------------------------
+ *
+ * open.c
+ * Win32 open() replacement
+ *
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ *
+ * src/port/open.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifdef WIN32
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <windows.h>
+#include <fcntl.h>
+#include <assert.h>
+
+
+static int
+openFlagsToCreateFileFlags(int openFlags)
+{
+ switch (openFlags & (O_CREAT | O_TRUNC | O_EXCL))
+ {
+ /* O_EXCL is meaningless without O_CREAT */
+ case 0:
+ case O_EXCL:
+ return OPEN_EXISTING;
+
+ case O_CREAT:
+ return OPEN_ALWAYS;
+
+ /* O_EXCL is meaningless without O_CREAT */
+ case O_TRUNC:
+ case O_TRUNC | O_EXCL:
+ return TRUNCATE_EXISTING;
+
+ case O_CREAT | O_TRUNC:
+ return CREATE_ALWAYS;
+
+ /* O_TRUNC is meaningless with O_CREAT */
+ case O_CREAT | O_EXCL:
+ case O_CREAT | O_TRUNC | O_EXCL:
+ return CREATE_NEW;
+ }
+
+ /* will never get here */
+ return 0;
+}
+
+/*
+ * - file attribute setting, based on fileMode?
+ */
+int
+pgwin32_open(const char *fileName, int fileFlags,...)
+{
+ int fd;
+ HANDLE h = INVALID_HANDLE_VALUE;
+ SECURITY_ATTRIBUTES sa;
+ int loops = 0;
+
+ /* Check that we can handle the request */
+ assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND |
+ (O_RANDOM | O_SEQUENTIAL | O_TEMPORARY) |
+ _O_SHORT_LIVED | O_DSYNC | O_DIRECT |
+ (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags);
+
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ while ((h = CreateFile(fileName,
+ /* cannot use O_RDONLY, as it == 0 */
+ (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
+ ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ),
+ /* These flags allow concurrent rename/unlink */
+ (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
+ &sa,
+ openFlagsToCreateFileFlags(fileFlags),
+ FILE_ATTRIBUTE_NORMAL |
+ ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) |
+ ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) |
+ ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) |
+ ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) |
+ ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) |
+ ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0),
+ NULL)) == INVALID_HANDLE_VALUE)
+ {
+ /*
+ * Sharing violation or locking error can indicate antivirus, backup
+ * or similar software that's locking the file. Try again for 30
+ * seconds before giving up.
+ */
+ DWORD err = GetLastError();
+
+ if (err == ERROR_SHARING_VIOLATION ||
+ err == ERROR_LOCK_VIOLATION)
+ {
+ pg_usleep(100000);
+ loops++;
+
+#ifndef FRONTEND
+ if (loops == 50)
+ ereport(LOG,
+ (errmsg("could not open file \"%s\": %s", fileName,
+ (err == ERROR_SHARING_VIOLATION) ? _("sharing violation") : _("lock violation")),
+ errdetail("Continuing to retry for 30 seconds."),
+ errhint("You might have antivirus, backup, or similar software interfering with the database system.")));
+#endif
+
+ if (loops < 300)
+ continue;
+ }
+
+ _dosmaperr(err);
+ return -1;
+ }
+
+ /* _open_osfhandle will, on error, set errno accordingly */
+ if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0)
+ CloseHandle(h); /* will not affect errno */
+ else if (fileFlags & (O_TEXT | O_BINARY) &&
+ _setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0)
+ {
+ _close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+FILE *
+pgwin32_fopen(const char *fileName, const char *mode)
+{
+ int openmode = 0;
+ int fd;
+
+ if (strstr(mode, "r+"))
+ openmode |= O_RDWR;
+ else if (strchr(mode, 'r'))
+ openmode |= O_RDONLY;
+ if (strstr(mode, "w+"))
+ openmode |= O_RDWR | O_CREAT | O_TRUNC;
+ else if (strchr(mode, 'w'))
+ openmode |= O_WRONLY | O_CREAT | O_TRUNC;
+ if (strchr(mode, 'a'))
+ openmode |= O_WRONLY | O_CREAT | O_APPEND;
+
+ if (strchr(mode, 'b'))
+ openmode |= O_BINARY;
+ if (strchr(mode, 't'))
+ openmode |= O_TEXT;
+
+ fd = pgwin32_open(fileName, openmode);
+ if (fd == -1)
+ return NULL;
+ return _fdopen(fd, mode);
+}
+
+#endif
diff --git a/libpq/win32/pgsleep.c b/libpq/win32/pgsleep.c
new file mode 100644
index 0000000..ecefe04
--- /dev/null
+++ b/libpq/win32/pgsleep.c
@@ -0,0 +1,63 @@
+/*-------------------------------------------------------------------------
+ *
+ * pgsleep.c
+ * Portable delay handling.
+ *
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ *
+ * src/port/pgsleep.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "c.h"
+
+#include <unistd.h>
+#include <sys/time.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+/*
+ * In a Windows backend, we don't use this implementation, but rather
+ * the signal-aware version in src/backend/port/win32/signal.c.
+ */
+#if defined(FRONTEND) || !defined(WIN32)
+
+/*
+ * pg_usleep --- delay the specified number of microseconds.
+ *
+ * NOTE: although the delay is specified in microseconds, the effective
+ * resolution is only 1/HZ, or 10 milliseconds, on most Unixen. Expect
+ * the requested delay to be rounded up to the next resolution boundary.
+ *
+ * On machines where "long" is 32 bits, the maximum delay is ~2000 seconds.
+ *
+ * CAUTION: the behavior when a signal arrives during the sleep is platform
+ * dependent. On most Unix-ish platforms, a signal does not terminate the
+ * sleep; but on some, it will (the Windows implementation also allows signals
+ * to terminate pg_usleep). And there are platforms where not only does a
+ * signal not terminate the sleep, but it actually resets the timeout counter
+ * so that the sleep effectively starts over! It is therefore rather hazardous
+ * to use this for long sleeps; a continuing stream of signal events could
+ * prevent the sleep from ever terminating. Better practice for long sleeps
+ * is to use WaitLatch() with a timeout.
+ */
+void
+pg_usleep(long microsec)
+{
+ if (microsec > 0)
+ {
+#ifndef WIN32
+ struct timeval delay;
+
+ delay.tv_sec = microsec / 1000000L;
+ delay.tv_usec = microsec % 1000000L;
+ (void) select(0, NULL, NULL, NULL, &delay);
+#else
+ SleepEx((microsec < 500 ? 1 : (microsec + 500) / 1000), FALSE);
+#endif
+ }
+}
+
+#endif /* defined(FRONTEND) || !defined(WIN32) */
diff --git a/libpq/win32/pthread-win32.c b/libpq/win32/pthread-win32.c
new file mode 100644
index 0000000..68dfefc
--- /dev/null
+++ b/libpq/win32/pthread-win32.c
@@ -0,0 +1,61 @@
+/*-------------------------------------------------------------------------
+*
+* pthread-win32.c
+* partial pthread implementation for win32
+*
+* Copyright (c) 2004-2016, PostgreSQL Global Development Group
+* IDENTIFICATION
+* src/interfaces/libpq/pthread-win32.c
+*
+*-------------------------------------------------------------------------
+*/
+
+#include "postgres_fe.h"
+
+#include <windows.h>
+#include "pthread-win32.h"
+
+DWORD
+pthread_self(void)
+{
+ return GetCurrentThreadId();
+}
+
+void
+pthread_setspecific(pthread_key_t key, void *val)
+{
+}
+
+void *
+pthread_getspecific(pthread_key_t key)
+{
+ return NULL;
+}
+
+int
+pthread_mutex_init(pthread_mutex_t *mp, void *attr)
+{
+ *mp = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION));
+ if (!*mp)
+ return 1;
+ InitializeCriticalSection(*mp);
+ return 0;
+}
+
+int
+pthread_mutex_lock(pthread_mutex_t *mp)
+{
+ if (!*mp)
+ return 1;
+ EnterCriticalSection(*mp);
+ return 0;
+}
+
+int
+pthread_mutex_unlock(pthread_mutex_t *mp)
+{
+ if (!*mp)
+ return 1;
+ LeaveCriticalSection(*mp);
+ return 0;
+}
diff --git a/libpq/win32/pthread-win32.h b/libpq/win32/pthread-win32.h
new file mode 100644
index 0000000..97ccc17
--- /dev/null
+++ b/libpq/win32/pthread-win32.h
@@ -0,0 +1,22 @@
+/*
+ * src/port/pthread-win32.h
+ */
+#ifndef __PTHREAD_H
+#define __PTHREAD_H
+
+typedef ULONG pthread_key_t;
+typedef CRITICAL_SECTION *pthread_mutex_t;
+typedef int pthread_once_t;
+
+DWORD pthread_self(void);
+
+void pthread_setspecific(pthread_key_t, void *);
+void *pthread_getspecific(pthread_key_t);
+
+int pthread_mutex_init(pthread_mutex_t *, void *attr);
+int pthread_mutex_lock(pthread_mutex_t *);
+
+/* blocking */
+int pthread_mutex_unlock(pthread_mutex_t *);
+
+#endif
diff --git a/libpq/win32/snprintf.c b/libpq/win32/snprintf.c
new file mode 100644
index 0000000..62b23b0
--- /dev/null
+++ b/libpq/win32/snprintf.c
@@ -0,0 +1,1141 @@
+/*
+ * Copyright (c) 1983, 1995, 1996 Eric P. Allman
+ * Copyright (c) 1988, 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.
+ * 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.
+ *
+ * src/port/snprintf.c
+ */
+
+#include "c.h"
+
+#include <ctype.h>
+#ifdef _MSC_VER
+#include <float.h> /* for _isnan */
+#endif
+#include <limits.h>
+#include <math.h>
+#ifndef WIN32
+#include <sys/ioctl.h>
+#endif
+#include <sys/param.h>
+
+#ifndef NL_ARGMAX
+#define NL_ARGMAX 16
+#endif
+
+
+/*
+ * SNPRINTF, VSNPRINTF and friends
+ *
+ * These versions have been grabbed off the net. They have been
+ * cleaned up to compile properly and support for most of the Single Unix
+ * Specification has been added. Remaining unimplemented features are:
+ *
+ * 1. No locale support: the radix character is always '.' and the '
+ * (single quote) format flag is ignored.
+ *
+ * 2. No support for the "%n" format specification.
+ *
+ * 3. No support for wide characters ("lc" and "ls" formats).
+ *
+ * 4. No support for "long double" ("Lf" and related formats).
+ *
+ * 5. Space and '#' flags are not implemented.
+ *
+ *
+ * The result values of these functions are not the same across different
+ * platforms. This implementation is compatible with the Single Unix Spec:
+ *
+ * 1. -1 is returned only if processing is abandoned due to an invalid
+ * parameter, such as incorrect format string. (Although not required by
+ * the spec, this happens only when no characters have yet been transmitted
+ * to the destination.)
+ *
+ * 2. For snprintf and sprintf, 0 is returned if str == NULL or count == 0;
+ * no data has been stored.
+ *
+ * 3. Otherwise, the number of bytes actually transmitted to the destination
+ * is returned (excluding the trailing '\0' for snprintf and sprintf).
+ *
+ * For snprintf with nonzero count, the result cannot be more than count-1
+ * (a trailing '\0' is always stored); it is not possible to distinguish
+ * buffer overrun from exact fit. This is unlike some implementations that
+ * return the number of bytes that would have been needed for the complete
+ * result string.
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point. (now it does ... tgl)
+ **************************************************************/
+
+/* Prevent recursion */
+#undef vsnprintf
+#undef snprintf
+#undef sprintf
+#undef vfprintf
+#undef fprintf
+#undef printf
+
+/* Info about where the formatted output is going */
+typedef struct
+{
+ char *bufptr; /* next buffer output position */
+ char *bufstart; /* first buffer element */
+ char *bufend; /* last buffer element, or NULL */
+ /* bufend == NULL is for sprintf, where we assume buf is big enough */
+ FILE *stream; /* eventual output destination, or NULL */
+ int nchars; /* # chars already sent to stream */
+ bool failed; /* call is a failure; errno is set */
+} PrintfTarget;
+
+/*
+ * Info about the type and value of a formatting parameter. Note that we
+ * don't currently support "long double", "wint_t", or "wchar_t *" data,
+ * nor the '%n' formatting code; else we'd need more types. Also, at this
+ * level we need not worry about signed vs unsigned values.
+ */
+typedef enum
+{
+ ATYPE_NONE = 0,
+ ATYPE_INT,
+ ATYPE_LONG,
+ ATYPE_LONGLONG,
+ ATYPE_DOUBLE,
+ ATYPE_CHARPTR
+} PrintfArgType;
+
+typedef union
+{
+ int i;
+ long l;
+ int64 ll;
+ double d;
+ char *cptr;
+} PrintfArgValue;
+
+
+static void flushbuffer(PrintfTarget *target);
+static void dopr(PrintfTarget *target, const char *format, va_list args);
+
+
+int
+pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+ PrintfTarget target;
+
+ if (str == NULL || count == 0)
+ return 0;
+ target.bufstart = target.bufptr = str;
+ target.bufend = str + count - 1;
+ target.stream = NULL;
+ /* target.nchars is unused in this case */
+ target.failed = false;
+ dopr(&target, fmt, args);
+ *(target.bufptr) = '\0';
+ return target.failed ? -1 : (target.bufptr - target.bufstart);
+}
+
+int
+pg_snprintf(char *str, size_t count, const char *fmt,...)
+{
+ int len;
+ va_list args;
+
+ va_start(args, fmt);
+ len = pg_vsnprintf(str, count, fmt, args);
+ va_end(args);
+ return len;
+}
+
+static int
+pg_vsprintf(char *str, const char *fmt, va_list args)
+{
+ PrintfTarget target;
+
+ if (str == NULL)
+ return 0;
+ target.bufstart = target.bufptr = str;
+ target.bufend = NULL;
+ target.stream = NULL;
+ /* target.nchars is unused in this case */
+ target.failed = false;
+ dopr(&target, fmt, args);
+ *(target.bufptr) = '\0';
+ return target.failed ? -1 : (target.bufptr - target.bufstart);
+}
+
+int
+pg_sprintf(char *str, const char *fmt,...)
+{
+ int len;
+ va_list args;
+
+ va_start(args, fmt);
+ len = pg_vsprintf(str, fmt, args);
+ va_end(args);
+ return len;
+}
+
+int
+pg_vfprintf(FILE *stream, const char *fmt, va_list args)
+{
+ PrintfTarget target;
+ char buffer[1024]; /* size is arbitrary */
+
+ if (stream == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ target.bufstart = target.bufptr = buffer;
+ target.bufend = buffer + sizeof(buffer) - 1;
+ target.stream = stream;
+ target.nchars = 0;
+ target.failed = false;
+ dopr(&target, fmt, args);
+ /* dump any remaining buffer contents */
+ flushbuffer(&target);
+ return target.failed ? -1 : target.nchars;
+}
+
+int
+pg_fprintf(FILE *stream, const char *fmt,...)
+{
+ int len;
+ va_list args;
+
+ va_start(args, fmt);
+ len = pg_vfprintf(stream, fmt, args);
+ va_end(args);
+ return len;
+}
+
+int
+pg_printf(const char *fmt,...)
+{
+ int len;
+ va_list args;
+
+ va_start(args, fmt);
+ len = pg_vfprintf(stdout, fmt, args);
+ va_end(args);
+ return len;
+}
+
+/*
+ * Attempt to write the entire buffer to target->stream; discard the entire
+ * buffer in any case. Call this only when target->stream is defined.
+ */
+static void
+flushbuffer(PrintfTarget *target)
+{
+ size_t nc = target->bufptr - target->bufstart;
+
+ if (!target->failed && nc > 0)
+ {
+ size_t written;
+
+ written = fwrite(target->bufstart, 1, nc, target->stream);
+ target->nchars += written;
+ if (written != nc)
+ target->failed = true;
+ }
+ target->bufptr = target->bufstart;
+}
+
+
+static void fmtstr(char *value, int leftjust, int minlen, int maxwidth,
+ int pointflag, PrintfTarget *target);
+static void fmtptr(void *value, PrintfTarget *target);
+static void fmtint(int64 value, char type, int forcesign,
+ int leftjust, int minlen, int zpad, int precision, int pointflag,
+ PrintfTarget *target);
+static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target);
+static void fmtfloat(double value, char type, int forcesign,
+ int leftjust, int minlen, int zpad, int precision, int pointflag,
+ PrintfTarget *target);
+static void dostr(const char *str, int slen, PrintfTarget *target);
+static void dopr_outch(int c, PrintfTarget *target);
+static int adjust_sign(int is_negative, int forcesign, int *signvalue);
+static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen);
+static void leading_pad(int zpad, int *signvalue, int *padlen,
+ PrintfTarget *target);
+static void trailing_pad(int *padlen, PrintfTarget *target);
+
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+static void
+dopr(PrintfTarget *target, const char *format, va_list args)
+{
+ const char *format_start = format;
+ int ch;
+ bool have_dollar;
+ bool have_non_dollar;
+ bool have_star;
+ bool afterstar;
+ int accum;
+ int longlongflag;
+ int longflag;
+ int pointflag;
+ int leftjust;
+ int fieldwidth;
+ int precision;
+ int zpad;
+ int forcesign;
+ int last_dollar;
+ int fmtpos;
+ int cvalue;
+ int64 numvalue;
+ double fvalue;
+ char *strvalue;
+ int i;
+ PrintfArgType argtypes[NL_ARGMAX + 1];
+ PrintfArgValue argvalues[NL_ARGMAX + 1];
+
+ /*
+ * Parse the format string to determine whether there are %n$ format
+ * specs, and identify the types and order of the format parameters.
+ */
+ have_dollar = have_non_dollar = false;
+ last_dollar = 0;
+ MemSet(argtypes, 0, sizeof(argtypes));
+
+ while ((ch = *format++) != '\0')
+ {
+ if (ch != '%')
+ continue;
+ longflag = longlongflag = pointflag = 0;
+ fmtpos = accum = 0;
+ afterstar = false;
+nextch1:
+ ch = *format++;
+ if (ch == '\0')
+ break; /* illegal, but we don't complain */
+ switch (ch)
+ {
+ case '-':
+ case '+':
+ goto nextch1;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ accum = accum * 10 + (ch - '0');
+ goto nextch1;
+ case '.':
+ pointflag = 1;
+ accum = 0;
+ goto nextch1;
+ case '*':
+ if (afterstar)
+ have_non_dollar = true; /* multiple stars */
+ afterstar = true;
+ accum = 0;
+ goto nextch1;
+ case '$':
+ have_dollar = true;
+ if (accum <= 0 || accum > NL_ARGMAX)
+ goto bad_format;
+ if (afterstar)
+ {
+ if (argtypes[accum] &&
+ argtypes[accum] != ATYPE_INT)
+ goto bad_format;
+ argtypes[accum] = ATYPE_INT;
+ last_dollar = Max(last_dollar, accum);
+ afterstar = false;
+ }
+ else
+ fmtpos = accum;
+ accum = 0;
+ goto nextch1;
+ case 'l':
+ if (longflag)
+ longlongflag = 1;
+ else
+ longflag = 1;
+ goto nextch1;
+ case 'z':
+#if SIZEOF_SIZE_T == 8
+#ifdef HAVE_LONG_INT_64
+ longflag = 1;
+#elif defined(HAVE_LONG_LONG_INT_64)
+ longlongflag = 1;
+#else
+#error "Don't know how to print 64bit integers"
+#endif
+#else
+ /* assume size_t is same size as int */
+#endif
+ goto nextch1;
+ case 'h':
+ case '\'':
+ /* ignore these */
+ goto nextch1;
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if (fmtpos)
+ {
+ PrintfArgType atype;
+
+ if (longlongflag)
+ atype = ATYPE_LONGLONG;
+ else if (longflag)
+ atype = ATYPE_LONG;
+ else
+ atype = ATYPE_INT;
+ if (argtypes[fmtpos] &&
+ argtypes[fmtpos] != atype)
+ goto bad_format;
+ argtypes[fmtpos] = atype;
+ last_dollar = Max(last_dollar, fmtpos);
+ }
+ else
+ have_non_dollar = true;
+ break;
+ case 'c':
+ if (fmtpos)
+ {
+ if (argtypes[fmtpos] &&
+ argtypes[fmtpos] != ATYPE_INT)
+ goto bad_format;
+ argtypes[fmtpos] = ATYPE_INT;
+ last_dollar = Max(last_dollar, fmtpos);
+ }
+ else
+ have_non_dollar = true;
+ break;
+ case 's':
+ case 'p':
+ if (fmtpos)
+ {
+ if (argtypes[fmtpos] &&
+ argtypes[fmtpos] != ATYPE_CHARPTR)
+ goto bad_format;
+ argtypes[fmtpos] = ATYPE_CHARPTR;
+ last_dollar = Max(last_dollar, fmtpos);
+ }
+ else
+ have_non_dollar = true;
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (fmtpos)
+ {
+ if (argtypes[fmtpos] &&
+ argtypes[fmtpos] != ATYPE_DOUBLE)
+ goto bad_format;
+ argtypes[fmtpos] = ATYPE_DOUBLE;
+ last_dollar = Max(last_dollar, fmtpos);
+ }
+ else
+ have_non_dollar = true;
+ break;
+ case '%':
+ break;
+ }
+
+ /*
+ * If we finish the spec with afterstar still set, there's a
+ * non-dollar star in there.
+ */
+ if (afterstar)
+ have_non_dollar = true;
+ }
+
+ /* Per spec, you use either all dollar or all not. */
+ if (have_dollar && have_non_dollar)
+ goto bad_format;
+
+ /*
+ * In dollar mode, collect the arguments in physical order.
+ */
+ for (i = 1; i <= last_dollar; i++)
+ {
+ switch (argtypes[i])
+ {
+ case ATYPE_NONE:
+ goto bad_format;
+ case ATYPE_INT:
+ argvalues[i].i = va_arg(args, int);
+ break;
+ case ATYPE_LONG:
+ argvalues[i].l = va_arg(args, long);
+ break;
+ case ATYPE_LONGLONG:
+ argvalues[i].ll = va_arg(args, int64);
+ break;
+ case ATYPE_DOUBLE:
+ argvalues[i].d = va_arg(args, double);
+ break;
+ case ATYPE_CHARPTR:
+ argvalues[i].cptr = va_arg(args, char *);
+ break;
+ }
+ }
+
+ /*
+ * At last we can parse the format for real.
+ */
+ format = format_start;
+ while ((ch = *format++) != '\0')
+ {
+ if (target->failed)
+ break;
+
+ if (ch != '%')
+ {
+ dopr_outch(ch, target);
+ continue;
+ }
+ fieldwidth = precision = zpad = leftjust = forcesign = 0;
+ longflag = longlongflag = pointflag = 0;
+ fmtpos = accum = 0;
+ have_star = afterstar = false;
+nextch2:
+ ch = *format++;
+ if (ch == '\0')
+ break; /* illegal, but we don't complain */
+ switch (ch)
+ {
+ case '-':
+ leftjust = 1;
+ goto nextch2;
+ case '+':
+ forcesign = 1;
+ goto nextch2;
+ case '0':
+ /* set zero padding if no nonzero digits yet */
+ if (accum == 0 && !pointflag)
+ zpad = '0';
+ /* FALL THRU */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ accum = accum * 10 + (ch - '0');
+ goto nextch2;
+ case '.':
+ if (have_star)
+ have_star = false;
+ else
+ fieldwidth = accum;
+ pointflag = 1;
+ accum = 0;
+ goto nextch2;
+ case '*':
+ if (have_dollar)
+ {
+ /* process value after reading n$ */
+ afterstar = true;
+ }
+ else
+ {
+ /* fetch and process value now */
+ int starval = va_arg(args, int);
+
+ if (pointflag)
+ {
+ precision = starval;
+ if (precision < 0)
+ {
+ precision = 0;
+ pointflag = 0;
+ }
+ }
+ else
+ {
+ fieldwidth = starval;
+ if (fieldwidth < 0)
+ {
+ leftjust = 1;
+ fieldwidth = -fieldwidth;
+ }
+ }
+ }
+ have_star = true;
+ accum = 0;
+ goto nextch2;
+ case '$':
+ if (afterstar)
+ {
+ /* fetch and process star value */
+ int starval = argvalues[accum].i;
+
+ if (pointflag)
+ {
+ precision = starval;
+ if (precision < 0)
+ {
+ precision = 0;
+ pointflag = 0;
+ }
+ }
+ else
+ {
+ fieldwidth = starval;
+ if (fieldwidth < 0)
+ {
+ leftjust = 1;
+ fieldwidth = -fieldwidth;
+ }
+ }
+ afterstar = false;
+ }
+ else
+ fmtpos = accum;
+ accum = 0;
+ goto nextch2;
+ case 'l':
+ if (longflag)
+ longlongflag = 1;
+ else
+ longflag = 1;
+ goto nextch2;
+ case 'z':
+#if SIZEOF_SIZE_T == 8
+#ifdef HAVE_LONG_INT_64
+ longflag = 1;
+#elif defined(HAVE_LONG_LONG_INT_64)
+ longlongflag = 1;
+#else
+#error "Don't know how to print 64bit integers"
+#endif
+#else
+ /* assume size_t is same size as int */
+#endif
+ goto nextch2;
+ case 'h':
+ case '\'':
+ /* ignore these */
+ goto nextch2;
+ case 'd':
+ case 'i':
+ if (!have_star)
+ {
+ if (pointflag)
+ precision = accum;
+ else
+ fieldwidth = accum;
+ }
+ if (have_dollar)
+ {
+ if (longlongflag)
+ numvalue = argvalues[fmtpos].ll;
+ else if (longflag)
+ numvalue = argvalues[fmtpos].l;
+ else
+ numvalue = argvalues[fmtpos].i;
+ }
+ else
+ {
+ if (longlongflag)
+ numvalue = va_arg(args, int64);
+ else if (longflag)
+ numvalue = va_arg(args, long);
+ else
+ numvalue = va_arg(args, int);
+ }
+ fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad,
+ precision, pointflag, target);
+ break;
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if (!have_star)
+ {
+ if (pointflag)
+ precision = accum;
+ else
+ fieldwidth = accum;
+ }
+ if (have_dollar)
+ {
+ if (longlongflag)
+ numvalue = (uint64) argvalues[fmtpos].ll;
+ else if (longflag)
+ numvalue = (unsigned long) argvalues[fmtpos].l;
+ else
+ numvalue = (unsigned int) argvalues[fmtpos].i;
+ }
+ else
+ {
+ if (longlongflag)
+ numvalue = (uint64) va_arg(args, int64);
+ else if (longflag)
+ numvalue = (unsigned long) va_arg(args, long);
+ else
+ numvalue = (unsigned int) va_arg(args, int);
+ }
+ fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad,
+ precision, pointflag, target);
+ break;
+ case 'c':
+ if (!have_star)
+ {
+ if (pointflag)
+ precision = accum;
+ else
+ fieldwidth = accum;
+ }
+ if (have_dollar)
+ cvalue = (unsigned char) argvalues[fmtpos].i;
+ else
+ cvalue = (unsigned char) va_arg(args, int);
+ fmtchar(cvalue, leftjust, fieldwidth, target);
+ break;
+ case 's':
+ if (!have_star)
+ {
+ if (pointflag)
+ precision = accum;
+ else
+ fieldwidth = accum;
+ }
+ if (have_dollar)
+ strvalue = argvalues[fmtpos].cptr;
+ else
+ strvalue = va_arg(args, char *);
+ fmtstr(strvalue, leftjust, fieldwidth, precision, pointflag,
+ target);
+ break;
+ case 'p':
+ /* fieldwidth/leftjust are ignored ... */
+ if (have_dollar)
+ strvalue = argvalues[fmtpos].cptr;
+ else
+ strvalue = va_arg(args, char *);
+ fmtptr((void *) strvalue, target);
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (!have_star)
+ {
+ if (pointflag)
+ precision = accum;
+ else
+ fieldwidth = accum;
+ }
+ if (have_dollar)
+ fvalue = argvalues[fmtpos].d;
+ else
+ fvalue = va_arg(args, double);
+ fmtfloat(fvalue, ch, forcesign, leftjust,
+ fieldwidth, zpad,
+ precision, pointflag,
+ target);
+ break;
+ case '%':
+ dopr_outch('%', target);
+ break;
+ }
+ }
+
+ return;
+
+bad_format:
+ errno = EINVAL;
+ target->failed = true;
+}
+
+static size_t
+pg_strnlen(const char *str, size_t maxlen)
+{
+ const char *p = str;
+
+ while (maxlen-- > 0 && *p)
+ p++;
+ return p - str;
+}
+
+static void
+fmtstr(char *value, int leftjust, int minlen, int maxwidth,
+ int pointflag, PrintfTarget *target)
+{
+ int padlen,
+ vallen; /* amount to pad */
+
+ /*
+ * If a maxwidth (precision) is specified, we must not fetch more bytes
+ * than that.
+ */
+ if (pointflag)
+ vallen = pg_strnlen(value, maxwidth);
+ else
+ vallen = strlen(value);
+
+ adjust_padlen(minlen, vallen, leftjust, &padlen);
+
+ while (padlen > 0)
+ {
+ dopr_outch(' ', target);
+ --padlen;
+ }
+
+ dostr(value, vallen, target);
+
+ trailing_pad(&padlen, target);
+}
+
+static void
+fmtptr(void *value, PrintfTarget *target)
+{
+ int vallen;
+ char convert[64];
+
+ /* we rely on regular C library's sprintf to do the basic conversion */
+ vallen = sprintf(convert, "%p", value);
+ if (vallen < 0)
+ target->failed = true;
+ else
+ dostr(convert, vallen, target);
+}
+
+static void
+fmtint(int64 value, char type, int forcesign, int leftjust,
+ int minlen, int zpad, int precision, int pointflag,
+ PrintfTarget *target)
+{
+ uint64 base;
+ int dosign;
+ const char *cvt = "0123456789abcdef";
+ int signvalue = 0;
+ char convert[64];
+ int vallen = 0;
+ int padlen = 0; /* amount to pad */
+ int zeropad; /* extra leading zeroes */
+
+ switch (type)
+ {
+ case 'd':
+ case 'i':
+ base = 10;
+ dosign = 1;
+ break;
+ case 'o':
+ base = 8;
+ dosign = 0;
+ break;
+ case 'u':
+ base = 10;
+ dosign = 0;
+ break;
+ case 'x':
+ base = 16;
+ dosign = 0;
+ break;
+ case 'X':
+ cvt = "0123456789ABCDEF";
+ base = 16;
+ dosign = 0;
+ break;
+ default:
+ return; /* keep compiler quiet */
+ }
+
+ /* Handle +/- */
+ if (dosign && adjust_sign((value < 0), forcesign, &signvalue))
+ value = -value;
+
+ /*
+ * SUS: the result of converting 0 with an explicit precision of 0 is no
+ * characters
+ */
+ if (value == 0 && pointflag && precision == 0)
+ vallen = 0;
+ else
+ {
+ /* make integer string */
+ uint64 uvalue = (uint64) value;
+
+ do
+ {
+ convert[vallen++] = cvt[uvalue % base];
+ uvalue = uvalue / base;
+ } while (uvalue);
+ }
+
+ zeropad = Max(0, precision - vallen);
+
+ adjust_padlen(minlen, vallen + zeropad, leftjust, &padlen);
+
+ leading_pad(zpad, &signvalue, &padlen, target);
+
+ while (zeropad-- > 0)
+ dopr_outch('0', target);
+
+ while (vallen > 0)
+ dopr_outch(convert[--vallen], target);
+
+ trailing_pad(&padlen, target);
+}
+
+static void
+fmtchar(int value, int leftjust, int minlen, PrintfTarget *target)
+{
+ int padlen = 0; /* amount to pad */
+
+ adjust_padlen(minlen, 1, leftjust, &padlen);
+
+ while (padlen > 0)
+ {
+ dopr_outch(' ', target);
+ --padlen;
+ }
+
+ dopr_outch(value, target);
+
+ trailing_pad(&padlen, target);
+}
+
+static void
+fmtfloat(double value, char type, int forcesign, int leftjust,
+ int minlen, int zpad, int precision, int pointflag,
+ PrintfTarget *target)
+{
+ int signvalue = 0;
+ int prec;
+ int vallen;
+ char fmt[32];
+ char convert[1024];
+ int zeropadlen = 0; /* amount to pad with zeroes */
+ int padlen = 0; /* amount to pad with spaces */
+
+ /*
+ * We rely on the regular C library's sprintf to do the basic conversion,
+ * then handle padding considerations here.
+ *
+ * The dynamic range of "double" is about 1E+-308 for IEEE math, and not
+ * too wildly more than that with other hardware. In "f" format, sprintf
+ * could therefore generate at most 308 characters to the left of the
+ * decimal point; while we need to allow the precision to get as high as
+ * 308+17 to ensure that we don't truncate significant digits from very
+ * small values. To handle both these extremes, we use a buffer of 1024
+ * bytes and limit requested precision to 350 digits; this should prevent
+ * buffer overrun even with non-IEEE math. If the original precision
+ * request was more than 350, separately pad with zeroes.
+ */
+ if (precision < 0) /* cover possible overflow of "accum" */
+ precision = 0;
+ prec = Min(precision, 350);
+
+ if (pointflag)
+ {
+ if (sprintf(fmt, "%%.%d%c", prec, type) < 0)
+ goto fail;
+ zeropadlen = precision - prec;
+ }
+ else if (sprintf(fmt, "%%%c", type) < 0)
+ goto fail;
+
+ if (!isnan(value) && adjust_sign((value < 0), forcesign, &signvalue))
+ value = -value;
+
+ vallen = sprintf(convert, fmt, value);
+ if (vallen < 0)
+ goto fail;
+
+ /* If it's infinity or NaN, forget about doing any zero-padding */
+ if (zeropadlen > 0 && !isdigit((unsigned char) convert[vallen - 1]))
+ zeropadlen = 0;
+
+ adjust_padlen(minlen, vallen + zeropadlen, leftjust, &padlen);
+
+ leading_pad(zpad, &signvalue, &padlen, target);
+
+ if (zeropadlen > 0)
+ {
+ /* If 'e' or 'E' format, inject zeroes before the exponent */
+ char *epos = strrchr(convert, 'e');
+
+ if (!epos)
+ epos = strrchr(convert, 'E');
+ if (epos)
+ {
+ /* pad after exponent */
+ dostr(convert, epos - convert, target);
+ while (zeropadlen-- > 0)
+ dopr_outch('0', target);
+ dostr(epos, vallen - (epos - convert), target);
+ }
+ else
+ {
+ /* no exponent, pad after the digits */
+ dostr(convert, vallen, target);
+ while (zeropadlen-- > 0)
+ dopr_outch('0', target);
+ }
+ }
+ else
+ {
+ /* no zero padding, just emit the number as-is */
+ dostr(convert, vallen, target);
+ }
+
+ trailing_pad(&padlen, target);
+ return;
+
+fail:
+ target->failed = true;
+}
+
+static void
+dostr(const char *str, int slen, PrintfTarget *target)
+{
+ while (slen > 0)
+ {
+ int avail;
+
+ if (target->bufend != NULL)
+ avail = target->bufend - target->bufptr;
+ else
+ avail = slen;
+ if (avail <= 0)
+ {
+ /* buffer full, can we dump to stream? */
+ if (target->stream == NULL)
+ return; /* no, lose the data */
+ flushbuffer(target);
+ continue;
+ }
+ avail = Min(avail, slen);
+ memmove(target->bufptr, str, avail);
+ target->bufptr += avail;
+ str += avail;
+ slen -= avail;
+ }
+}
+
+static void
+dopr_outch(int c, PrintfTarget *target)
+{
+ if (target->bufend != NULL && target->bufptr >= target->bufend)
+ {
+ /* buffer full, can we dump to stream? */
+ if (target->stream == NULL)
+ return; /* no, lose the data */
+ flushbuffer(target);
+ }
+ *(target->bufptr++) = c;
+}
+
+
+static int
+adjust_sign(int is_negative, int forcesign, int *signvalue)
+{
+ if (is_negative)
+ {
+ *signvalue = '-';
+ return true;
+ }
+ else if (forcesign)
+ *signvalue = '+';
+ return false;
+}
+
+
+static void
+adjust_padlen(int minlen, int vallen, int leftjust, int *padlen)
+{
+ *padlen = minlen - vallen;
+ if (*padlen < 0)
+ *padlen = 0;
+ if (leftjust)
+ *padlen = -(*padlen);
+}
+
+
+static void
+leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target)
+{
+ if (*padlen > 0 && zpad)
+ {
+ if (*signvalue)
+ {
+ dopr_outch(*signvalue, target);
+ --(*padlen);
+ *signvalue = 0;
+ }
+ while (*padlen > 0)
+ {
+ dopr_outch(zpad, target);
+ --(*padlen);
+ }
+ }
+ while (*padlen > (*signvalue != 0))
+ {
+ dopr_outch(' ', target);
+ --(*padlen);
+ }
+ if (*signvalue)
+ {
+ dopr_outch(*signvalue, target);
+ if (*padlen > 0)
+ --(*padlen);
+ else if (*padlen < 0)
+ ++(*padlen);
+ }
+}
+
+
+static void
+trailing_pad(int *padlen, PrintfTarget *target)
+{
+ while (*padlen < 0)
+ {
+ dopr_outch(' ', target);
+ ++(*padlen);
+ }
+}
diff --git a/libpq/win32/system.c b/libpq/win32/system.c
new file mode 100644
index 0000000..15b6e37
--- /dev/null
+++ b/libpq/win32/system.c
@@ -0,0 +1,119 @@
+/*-------------------------------------------------------------------------
+ *
+ * system.c
+ * Win32 system() and popen() replacements
+ *
+ *
+ * Win32 needs double quotes at the beginning and end of system()
+ * strings. If not, it gets confused with multiple quoted strings.
+ * It also requires double-quotes around the executable name and
+ * any files used for redirection. Filter other args through
+ * appendShellString() to quote them.
+ *
+ * Generated using Win32 "CMD /?":
+ *
+ * 1. If all of the following conditions are met, then quote characters
+ * on the command line are preserved:
+ *
+ * - no /S switch
+ * - exactly two quote characters
+ * - no special characters between the two quote characters, where special
+ * is one of: &<>()@^|
+ * - there are one or more whitespace characters between the two quote
+ * characters
+ * - the string between the two quote characters is the name of an
+ * executable file.
+ *
+ * 2. Otherwise, old behavior is to see if the first character is a quote
+ * character and if so, strip the leading character and remove the last
+ * quote character on the command line, preserving any text after the last
+ * quote character.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ *
+ * src/port/system.c
+ *
+ *-------------------------------------------------------------------------
+ */
+int a;
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <windows.h>
+#include <fcntl.h>
+
+#undef system
+#undef popen
+
+int
+pgwin32_system(const char *command)
+{
+ size_t cmdlen = strlen(command);
+ char *buf;
+ int save_errno;
+ int res;
+
+ /*
+ * Create a malloc'd copy of the command string, enclosed with an extra
+ * pair of quotes
+ */
+ buf = malloc(cmdlen + 2 + 1);
+ if (buf == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ buf[0] = '"';
+ memcpy(&buf[1], command, cmdlen);
+ buf[cmdlen + 1] = '"';
+ buf[cmdlen + 2] = '\0';
+
+ res = system(buf);
+
+ save_errno = errno;
+ free(buf);
+ errno = save_errno;
+
+ return res;
+}
+
+
+FILE *
+pgwin32_popen(const char *command, const char *type)
+{
+ size_t cmdlen = strlen(command);
+ char *buf;
+ int save_errno;
+ FILE *res;
+
+ /*
+ * Create a malloc'd copy of the command string, enclosed with an extra
+ * pair of quotes
+ */
+ buf = malloc(cmdlen + 2 + 1);
+ if (buf == NULL)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+ buf[0] = '"';
+ memcpy(&buf[1], command, cmdlen);
+ buf[cmdlen + 1] = '"';
+ buf[cmdlen + 2] = '\0';
+
+ res = _popen(buf, type);
+
+ save_errno = errno;
+ free(buf);
+ errno = save_errno;
+
+ return res;
+}
+
+#endif
diff --git a/libpq/win32/win32.c b/libpq/win32/win32.c
new file mode 100644
index 0000000..1b7ad37
--- /dev/null
+++ b/libpq/win32/win32.c
@@ -0,0 +1,327 @@
+/*
+ * src/interfaces/libpq/win32.c
+ *
+ *
+ * FILE
+ * win32.c
+ *
+ * DESCRIPTION
+ * Win32 support functions.
+ *
+ * Contains table and functions for looking up win32 socket error
+ * descriptions. But will/may contain other win32 helper functions
+ * for libpq.
+ *
+ * The error constants are taken from the Frambak Bakfram LGSOCKET
+ * library guys who in turn took them from the Winsock FAQ.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ */
+
+/* Make stuff compile faster by excluding not used stuff */
+
+#define VC_EXTRALEAN
+#ifndef __MINGW32__
+#define NOGDI
+#endif
+#define NOCRYPT
+
+#include "postgres_fe.h"
+
+#include "win32.h"
+
+/* Declared here to avoid pulling in all includes, which causes name collisions */
+#ifdef ENABLE_NLS
+extern char *libpq_gettext(const char *msgid) pg_attribute_format_arg(1);
+#else
+#define libpq_gettext(x) (x)
+#endif
+
+
+static struct WSErrorEntry
+{
+ DWORD error;
+ const char *description;
+} WSErrors[] =
+
+{
+ {
+ 0, "No error"
+ },
+ {
+ WSAEINTR, "Interrupted system call"
+ },
+ {
+ WSAEBADF, "Bad file number"
+ },
+ {
+ WSAEACCES, "Permission denied"
+ },
+ {
+ WSAEFAULT, "Bad address"
+ },
+ {
+ WSAEINVAL, "Invalid argument"
+ },
+ {
+ WSAEMFILE, "Too many open sockets"
+ },
+ {
+ WSAEWOULDBLOCK, "Operation would block"
+ },
+ {
+ WSAEINPROGRESS, "Operation now in progress"
+ },
+ {
+ WSAEALREADY, "Operation already in progress"
+ },
+ {
+ WSAENOTSOCK, "Socket operation on non-socket"
+ },
+ {
+ WSAEDESTADDRREQ, "Destination address required"
+ },
+ {
+ WSAEMSGSIZE, "Message too long"
+ },
+ {
+ WSAEPROTOTYPE, "Protocol wrong type for socket"
+ },
+ {
+ WSAENOPROTOOPT, "Bad protocol option"
+ },
+ {
+ WSAEPROTONOSUPPORT, "Protocol not supported"
+ },
+ {
+ WSAESOCKTNOSUPPORT, "Socket type not supported"
+ },
+ {
+ WSAEOPNOTSUPP, "Operation not supported on socket"
+ },
+ {
+ WSAEPFNOSUPPORT, "Protocol family not supported"
+ },
+ {
+ WSAEAFNOSUPPORT, "Address family not supported"
+ },
+ {
+ WSAEADDRINUSE, "Address already in use"
+ },
+ {
+ WSAEADDRNOTAVAIL, "Cannot assign requested address"
+ },
+ {
+ WSAENETDOWN, "Network is down"
+ },
+ {
+ WSAENETUNREACH, "Network is unreachable"
+ },
+ {
+ WSAENETRESET, "Net connection reset"
+ },
+ {
+ WSAECONNABORTED, "Software caused connection abort"
+ },
+ {
+ WSAECONNRESET, "Connection reset by peer"
+ },
+ {
+ WSAENOBUFS, "No buffer space available"
+ },
+ {
+ WSAEISCONN, "Socket is already connected"
+ },
+ {
+ WSAENOTCONN, "Socket is not connected"
+ },
+ {
+ WSAESHUTDOWN, "Cannot send after socket shutdown"
+ },
+ {
+ WSAETOOMANYREFS, "Too many references, cannot splice"
+ },
+ {
+ WSAETIMEDOUT, "Connection timed out"
+ },
+ {
+ WSAECONNREFUSED, "Connection refused"
+ },
+ {
+ WSAELOOP, "Too many levels of symbolic links"
+ },
+ {
+ WSAENAMETOOLONG, "File name too long"
+ },
+ {
+ WSAEHOSTDOWN, "Host is down"
+ },
+ {
+ WSAEHOSTUNREACH, "No route to host"
+ },
+ {
+ WSAENOTEMPTY, "Directory not empty"
+ },
+ {
+ WSAEPROCLIM, "Too many processes"
+ },
+ {
+ WSAEUSERS, "Too many users"
+ },
+ {
+ WSAEDQUOT, "Disc quota exceeded"
+ },
+ {
+ WSAESTALE, "Stale NFS file handle"
+ },
+ {
+ WSAEREMOTE, "Too many levels of remote in path"
+ },
+ {
+ WSASYSNOTREADY, "Network system is unavailable"
+ },
+ {
+ WSAVERNOTSUPPORTED, "Winsock version out of range"
+ },
+ {
+ WSANOTINITIALISED, "WSAStartup not yet called"
+ },
+ {
+ WSAEDISCON, "Graceful shutdown in progress"
+ },
+ {
+ WSAHOST_NOT_FOUND, "Host not found"
+ },
+ {
+ WSATRY_AGAIN, "NA Host not found / SERVFAIL"
+ },
+ {
+ WSANO_RECOVERY, "Non recoverable FORMERR||REFUSED||NOTIMP"
+ },
+ {
+ WSANO_DATA, "No host data of that type was found"
+ },
+ {
+ 0, 0
+ } /* End of table */
+};
+
+
+/*
+ * Returns 0 if not found, linear but who cares, at this moment
+ * we're already in pain :)
+ */
+
+static int
+LookupWSErrorMessage(DWORD err, char *dest)
+{
+ struct WSErrorEntry *e;
+
+ for (e = WSErrors; e->description; e++)
+ {
+ if (e->error == err)
+ {
+ strcpy(dest, e->description);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+struct MessageDLL
+{
+ const char *dll_name;
+ void *handle;
+ int loaded; /* BOOL */
+} dlls[] =
+
+{
+ {
+ "netmsg.dll", 0, 0
+ },
+ {
+ "winsock.dll", 0, 0
+ },
+ {
+ "ws2_32.dll", 0, 0
+ },
+ {
+ "wsock32n.dll", 0, 0
+ },
+ {
+ "mswsock.dll", 0, 0
+ },
+ {
+ "ws2help.dll", 0, 0
+ },
+ {
+ "ws2thk.dll", 0, 0
+ },
+ {
+ 0, 0, 1
+ } /* Last one, no dll, always loaded */
+};
+
+#define DLLS_SIZE (sizeof(dlls)/sizeof(struct MessageDLL))
+
+/*
+ * Returns a description of the socket error by first trying
+ * to find it in the lookup table, and if that fails, tries
+ * to load any of the winsock dlls to find that message.
+ * The DLL thing works from Nt4 (spX ?) up, but some special
+ * versions of winsock might have this as well (seen on Win98 SE
+ * special install) / Magnus Naeslund (mag@fbab.net)
+ *
+ */
+
+const char *
+winsock_strerror(int err, char *strerrbuf, size_t buflen)
+{
+ unsigned long flags;
+ int offs,
+ i;
+ int success = LookupWSErrorMessage(err, strerrbuf);
+
+ for (i = 0; !success && i < DLLS_SIZE; i++)
+ {
+
+ if (!dlls[i].loaded)
+ {
+ dlls[i].loaded = 1; /* Only load once */
+ dlls[i].handle = (void *) LoadLibraryEx(
+ dlls[i].dll_name,
+ 0,
+ LOAD_LIBRARY_AS_DATAFILE);
+ }
+
+ if (dlls[i].dll_name && !dlls[i].handle)
+ continue; /* Didn't load */
+
+ flags = FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS
+ | (dlls[i].handle ? FORMAT_MESSAGE_FROM_HMODULE : 0);
+
+ success = 0 != FormatMessage(
+ flags,
+ dlls[i].handle, err,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
+ strerrbuf, buflen - 64,
+ 0
+ );
+ }
+
+ if (!success)
+ sprintf(strerrbuf, libpq_gettext("unrecognized socket error: 0x%08X/%d"), err, err);
+ else
+ {
+ strerrbuf[buflen - 1] = '\0';
+ offs = strlen(strerrbuf);
+ if (offs > (int) buflen - 64)
+ offs = buflen - 64;
+ sprintf(strerrbuf + offs, " (0x%08X/%d)", err, err);
+ }
+ return strerrbuf;
+}
diff --git a/libpq/win32/win32.h b/libpq/win32/win32.h
new file mode 100644
index 0000000..be00ea7
--- /dev/null
+++ b/libpq/win32/win32.h
@@ -0,0 +1,40 @@
+/*
+ * src/interfaces/libpq/win32.h
+ */
+#ifndef __win32_h_included
+#define __win32_h_included
+
+/*
+ * Some compatibility functions
+ */
+#ifdef __BORLANDC__
+#define _timeb timeb
+#define _ftime(a) ftime(a)
+#define _errno errno
+#define popen(a,b) _popen(a,b)
+#else
+/* open provided elsewhere */
+#define close(a) _close(a)
+#define read(a,b,c) _read(a,b,c)
+#define write(a,b,c) _write(a,b,c)
+#endif
+
+#undef EAGAIN /* doesn't apply on sockets */
+#undef EINTR
+#define EINTR WSAEINTR
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+#ifndef ECONNRESET
+#define ECONNRESET WSAECONNRESET
+#endif
+#ifndef EINPROGRESS
+#define EINPROGRESS WSAEINPROGRESS
+#endif
+
+/*
+ * support for handling Windows Socket errors
+ */
+extern const char *winsock_strerror(int err, char *strerrbuf, size_t buflen);
+
+#endif
diff --git a/libpq/win32/win32error.c b/libpq/win32/win32error.c
new file mode 100644
index 0000000..cf65225
--- /dev/null
+++ b/libpq/win32/win32error.c
@@ -0,0 +1,206 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32error.c
+ * Map win32 error codes to errno values
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/win32error.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+static const struct
+{
+ DWORD winerr;
+ int doserr;
+} doserrors[] =
+
+{
+ {
+ ERROR_INVALID_FUNCTION, EINVAL
+ },
+ {
+ ERROR_FILE_NOT_FOUND, ENOENT
+ },
+ {
+ ERROR_PATH_NOT_FOUND, ENOENT
+ },
+ {
+ ERROR_TOO_MANY_OPEN_FILES, EMFILE
+ },
+ {
+ ERROR_ACCESS_DENIED, EACCES
+ },
+ {
+ ERROR_INVALID_HANDLE, EBADF
+ },
+ {
+ ERROR_ARENA_TRASHED, ENOMEM
+ },
+ {
+ ERROR_NOT_ENOUGH_MEMORY, ENOMEM
+ },
+ {
+ ERROR_INVALID_BLOCK, ENOMEM
+ },
+ {
+ ERROR_BAD_ENVIRONMENT, E2BIG
+ },
+ {
+ ERROR_BAD_FORMAT, ENOEXEC
+ },
+ {
+ ERROR_INVALID_ACCESS, EINVAL
+ },
+ {
+ ERROR_INVALID_DATA, EINVAL
+ },
+ {
+ ERROR_INVALID_DRIVE, ENOENT
+ },
+ {
+ ERROR_CURRENT_DIRECTORY, EACCES
+ },
+ {
+ ERROR_NOT_SAME_DEVICE, EXDEV
+ },
+ {
+ ERROR_NO_MORE_FILES, ENOENT
+ },
+ {
+ ERROR_LOCK_VIOLATION, EACCES
+ },
+ {
+ ERROR_SHARING_VIOLATION, EACCES
+ },
+ {
+ ERROR_BAD_NETPATH, ENOENT
+ },
+ {
+ ERROR_NETWORK_ACCESS_DENIED, EACCES
+ },
+ {
+ ERROR_BAD_NET_NAME, ENOENT
+ },
+ {
+ ERROR_FILE_EXISTS, EEXIST
+ },
+ {
+ ERROR_CANNOT_MAKE, EACCES
+ },
+ {
+ ERROR_FAIL_I24, EACCES
+ },
+ {
+ ERROR_INVALID_PARAMETER, EINVAL
+ },
+ {
+ ERROR_NO_PROC_SLOTS, EAGAIN
+ },
+ {
+ ERROR_DRIVE_LOCKED, EACCES
+ },
+ {
+ ERROR_BROKEN_PIPE, EPIPE
+ },
+ {
+ ERROR_DISK_FULL, ENOSPC
+ },
+ {
+ ERROR_INVALID_TARGET_HANDLE, EBADF
+ },
+ {
+ ERROR_INVALID_HANDLE, EINVAL
+ },
+ {
+ ERROR_WAIT_NO_CHILDREN, ECHILD
+ },
+ {
+ ERROR_CHILD_NOT_COMPLETE, ECHILD
+ },
+ {
+ ERROR_DIRECT_ACCESS_HANDLE, EBADF
+ },
+ {
+ ERROR_NEGATIVE_SEEK, EINVAL
+ },
+ {
+ ERROR_SEEK_ON_DEVICE, EACCES
+ },
+ {
+ ERROR_DIR_NOT_EMPTY, ENOTEMPTY
+ },
+ {
+ ERROR_NOT_LOCKED, EACCES
+ },
+ {
+ ERROR_BAD_PATHNAME, ENOENT
+ },
+ {
+ ERROR_MAX_THRDS_REACHED, EAGAIN
+ },
+ {
+ ERROR_LOCK_FAILED, EACCES
+ },
+ {
+ ERROR_ALREADY_EXISTS, EEXIST
+ },
+ {
+ ERROR_FILENAME_EXCED_RANGE, ENOENT
+ },
+ {
+ ERROR_NESTING_NOT_ALLOWED, EAGAIN
+ },
+ {
+ ERROR_NOT_ENOUGH_QUOTA, ENOMEM
+ }
+};
+
+void
+_dosmaperr(unsigned long e)
+{
+ int i;
+
+ if (e == 0)
+ {
+ errno = 0;
+ return;
+ }
+
+ for (i = 0; i < lengthof(doserrors); i++)
+ {
+ if (doserrors[i].winerr == e)
+ {
+ int doserr = doserrors[i].doserr;
+
+#ifndef FRONTEND
+ ereport(DEBUG5,
+ (errmsg_internal("mapped win32 error code %lu to %d",
+ e, doserr)));
+#elif FRONTEND_DEBUG
+ fprintf(stderr, "mapped win32 error code %lu to %d", e, doserr);
+#endif
+ errno = doserr;
+ return;
+ }
+ }
+
+#ifndef FRONTEND
+ ereport(LOG,
+ (errmsg_internal("unrecognized win32 error code: %lu",
+ e)));
+#else
+ fprintf(stderr, "unrecognized win32 error code: %lu", e);
+#endif
+
+ errno = EINVAL;
+ return;
+}
diff --git a/libpq/win32/win32setlocale.c b/libpq/win32/win32setlocale.c
new file mode 100644
index 0000000..4abc7aa
--- /dev/null
+++ b/libpq/win32/win32setlocale.c
@@ -0,0 +1,189 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32setlocale.c
+ * Wrapper to work around bugs in Windows setlocale() implementation
+ *
+ * Copyright (c) 2011-2016, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/win32setlocale.c
+ *
+ *
+ * The setlocale() function in Windows is broken in two ways. First, it
+ * has a problem with locale names that have a dot in the country name. For
+ * example:
+ *
+ * "Chinese (Traditional)_Hong Kong S.A.R..950"
+ *
+ * For some reason, setlocale() doesn't accept that as argument, even though
+ * setlocale(LC_ALL, NULL) returns exactly that. Fortunately, it accepts
+ * various alternative names for such countries, so to work around the broken
+ * setlocale() function, we map the troublemaking locale names to accepted
+ * aliases, before calling setlocale().
+ *
+ * The second problem is that the locale name for "Norwegian (Bokm&aring;l)"
+ * contains a non-ASCII character. That's problematic, because it's not clear
+ * what encoding the locale name itself is supposed to be in, when you
+ * haven't yet set a locale. Also, it causes problems when the cluster
+ * contains databases with different encodings, as the locale name is stored
+ * in the pg_database system catalog. To work around that, when setlocale()
+ * returns that locale name, map it to a pure-ASCII alias for the same
+ * locale.
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#undef setlocale
+
+struct locale_map
+{
+ /*
+ * String in locale name to replace. Can be a single string (end is NULL),
+ * or separate start and end strings. If two strings are given, the locale
+ * name must contain both of them, and everything between them is
+ * replaced. This is used for a poor-man's regexp search, allowing
+ * replacement of "start.*end".
+ */
+ const char *locale_name_start;
+ const char *locale_name_end;
+
+ const char *replacement; /* string to replace the match with */
+};
+
+/*
+ * Mappings applied before calling setlocale(), to the argument.
+ */
+static const struct locale_map locale_map_argument[] = {
+ /*
+ * "HKG" is listed here:
+ * http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx
+ * (Country/Region Strings).
+ *
+ * "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the
+ * above list, but seems to work anyway.
+ */
+ {"Hong Kong S.A.R.", NULL, "HKG"},
+ {"U.A.E.", NULL, "ARE"},
+
+ /*
+ * The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't
+ * seem to recognize that. And Macau isn't listed in the table of accepted
+ * abbreviations linked above. Fortunately, "ZHM" seems to be accepted as
+ * an alias for "Chinese (Traditional)_Macau S.A.R..950". I'm not sure
+ * where "ZHM" comes from, must be some legacy naming scheme. But hey, it
+ * works.
+ *
+ * Note that unlike HKG and ARE, ZHM is an alias for the *whole* locale
+ * name, not just the country part.
+ *
+ * Some versions of Windows spell it "Macau", others "Macao".
+ */
+ {"Chinese (Traditional)_Macau S.A.R..950", NULL, "ZHM"},
+ {"Chinese_Macau S.A.R..950", NULL, "ZHM"},
+ {"Chinese (Traditional)_Macao S.A.R..950", NULL, "ZHM"},
+ {"Chinese_Macao S.A.R..950", NULL, "ZHM"},
+ {NULL, NULL, NULL}
+};
+
+/*
+ * Mappings applied after calling setlocale(), to its return value.
+ */
+static const struct locale_map locale_map_result[] = {
+ /*
+ * "Norwegian (Bokm&aring;l)" locale name contains the a-ring character.
+ * Map it to a pure-ASCII alias.
+ *
+ * It's not clear what encoding setlocale() uses when it returns the
+ * locale name, so to play it safe, we search for "Norwegian (Bok*l)".
+ */
+ {"Norwegian (Bokm", "l)_Norway", "Norwegian_Norway"},
+ {NULL, NULL, NULL}
+};
+
+#define MAX_LOCALE_NAME_LEN 100
+
+static const char *
+map_locale(const struct locale_map * map, const char *locale)
+{
+ static char aliasbuf[MAX_LOCALE_NAME_LEN];
+ int i;
+
+ /* Check if the locale name matches any of the problematic ones. */
+ for (i = 0; map[i].locale_name_start != NULL; i++)
+ {
+ const char *needle_start = map[i].locale_name_start;
+ const char *needle_end = map[i].locale_name_end;
+ const char *replacement = map[i].replacement;
+ char *match;
+ char *match_start = NULL;
+ char *match_end = NULL;
+
+ match = strstr(locale, needle_start);
+ if (match)
+ {
+ /*
+ * Found a match for the first part. If this was a two-part
+ * replacement, find the second part.
+ */
+ match_start = match;
+ if (needle_end)
+ {
+ match = strstr(match_start + strlen(needle_start), needle_end);
+ if (match)
+ match_end = match + strlen(needle_end);
+ else
+ match_start = NULL;
+ }
+ else
+ match_end = match_start + strlen(needle_start);
+ }
+
+ if (match_start)
+ {
+ /* Found a match. Replace the matched string. */
+ int matchpos = match_start - locale;
+ int replacementlen = strlen(replacement);
+ char *rest = match_end;
+ int restlen = strlen(rest);
+
+ /* check that the result fits in the static buffer */
+ if (matchpos + replacementlen + restlen + 1 > MAX_LOCALE_NAME_LEN)
+ return NULL;
+
+ memcpy(&aliasbuf[0], &locale[0], matchpos);
+ memcpy(&aliasbuf[matchpos], replacement, replacementlen);
+ /* includes null terminator */
+ memcpy(&aliasbuf[matchpos + replacementlen], rest, restlen + 1);
+
+ return aliasbuf;
+ }
+ }
+
+ /* no match, just return the original string */
+ return locale;
+}
+
+char *
+pgwin32_setlocale(int category, const char *locale)
+{
+ const char *argument;
+ char *result;
+
+ if (locale == NULL)
+ argument = NULL;
+ else
+ argument = map_locale(locale_map_argument, locale);
+
+ /* Call the real setlocale() function */
+ result = setlocale(category, argument);
+
+ /*
+ * setlocale() is specified to return a "char *" that the caller is
+ * forbidden to modify, so casting away the "const" is innocuous.
+ */
+ if (result)
+ result = (char *) map_locale(locale_map_result, result);
+
+ return result;
+}