{"thread":{"id":"28759","subject":"[PATCH v4 0/3] port upload-archive to Windows","startedAt":"2011-10-24T16:02:08Z","lastAt":"2011-11-15T21:30:40Z","messageCount":17,"participants":["Erik Faye-Lund","Jeff King","Thomas Rast","Andreas Schwab","Junio C Hamano"],"isPatch":true,"patchVersion":4,"patchTotal":3},"messages":[{"id":"178238","messageId":"1319472131-3968-1-git-send-email-kusmabite@gmail.com","threadId":"28759","inReplyTo":null,"subject":"[PATCH v4 0/3] port upload-archive to Windows","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-10-24T16:02:08Z","receivedAt":"2011-10-24T16:02:08Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"Here's a new iteration of this series. I delayed it until the\nimproved version of \"enter_repo: do not modify input\" hit master,\nwhich happened recently.\n\nThe important change in this iteration (besides the patch that\nalready propagated upstream) is that I've moved\ncompat/win32/sys/poll.[ch] out of the sys-folder (as XSI suggests).\nThis enables us to easily upgrade the poll-emulation without\nbreaking the Windows build in the process.\n\nErik Faye-Lund (3):\n  mingw: move poll out of sys-folder\n  compat/win32/poll.c: upgrade from upstream\n  upload-archive: use start_command instead of fork\n\n Makefile                 |    6 +-\n builtin/archive.c        |    6 +-\n builtin/upload-archive.c |   68 ++----\n compat/mingw.h           |    2 -\n compat/win32/poll.c      |  606 ++++++++++++++++++++++++++++++++++++++++++++++\n compat/win32/poll.h      |   53 ++++\n compat/win32/sys/poll.c  |  599 ---------------------------------------------\n compat/win32/sys/poll.h  |   53 ----\n t/t5000-tar-tree.sh      |   10 +-\n 9 files changed, 694 insertions(+), 709 deletions(-)\n create mode 100644 compat/win32/poll.c\n create mode 100644 compat/win32/poll.h\n delete mode 100644 compat/win32/sys/poll.c\n delete mode 100644 compat/win32/sys/poll.h\n\n-- \n1.7.7.msysgit.1.1.g7b316\n"},{"id":"178241","messageId":"1319472131-3968-2-git-send-email-kusmabite@gmail.com","threadId":"28759","inReplyTo":"1319472131-3968-1-git-send-email-kusmabite@gmail.com","subject":"[PATCH v4 1/3] mingw: move poll out of sys-folder","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-10-24T16:02:09Z","receivedAt":"2011-10-24T16:02:09Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"Both XSI and upstream Gnulib versions expects to find poll.h at\nthe root of some include path, not inside the sys-folder.\n\nThis helps us when upgrading Gnulib.\n\nSigned-off-by: Erik Faye-Lund <kusmabite@gmail.com>\n---\n Makefile                |    6 +-\n compat/win32/poll.c     |  599 +++++++++++++++++++++++++++++++++++++++++++++++\n compat/win32/poll.h     |   53 +++++\n compat/win32/sys/poll.c |  599 -----------------------------------------------\n compat/win32/sys/poll.h |   53 -----\n 5 files changed, 656 insertions(+), 654 deletions(-)\n create mode 100644 compat/win32/poll.c\n create mode 100644 compat/win32/poll.h\n delete mode 100644 compat/win32/sys/poll.c\n delete mode 100644 compat/win32/sys/poll.h\n\ndiff --git a/Makefile b/Makefile\nindex 3139c19..4c09b35 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1088,6 +1088,7 @@ ifeq ($(uname_S),Windows)\n \tNO_PREAD = YesPlease\n \tNEEDS_CRYPTO_WITH_SSL = YesPlease\n \tNO_LIBGEN_H = YesPlease\n+\tNO_SYS_POLL_H = YesPlease\n \tNO_SYMLINK_HEAD = YesPlease\n \tNO_IPV6 = YesPlease\n \tNO_SETENV = YesPlease\n@@ -1126,7 +1127,7 @@ ifeq ($(uname_S),Windows)\n \tBASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE\n \tCOMPAT_OBJS = compat/msvc.o compat/winansi.o \\\n \t\tcompat/win32/pthread.o compat/win32/syslog.o \\\n-\t\tcompat/win32/sys/poll.o compat/win32/dirent.o\n+\t\tcompat/win32/poll.o compat/win32/dirent.o\n \tCOMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\\\".exe\\\"\n \tBASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib\n \tEXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib\n@@ -1181,6 +1182,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n \tNO_PREAD = YesPlease\n \tNEEDS_CRYPTO_WITH_SSL = YesPlease\n \tNO_LIBGEN_H = YesPlease\n+\tNO_SYS_POLL_H = YesPlease\n \tNO_SYMLINK_HEAD = YesPlease\n \tNO_SETENV = YesPlease\n \tNO_UNSETENV = YesPlease\n@@ -1214,7 +1216,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n \tCOMPAT_CFLAGS += -DSTRIP_EXTENSION=\\\".exe\\\"\n \tCOMPAT_OBJS += compat/mingw.o compat/winansi.o \\\n \t\tcompat/win32/pthread.o compat/win32/syslog.o \\\n-\t\tcompat/win32/sys/poll.o compat/win32/dirent.o\n+\t\tcompat/win32/poll.o compat/win32/dirent.o\n \tEXTLIBS += -lws2_32\n \tPTHREAD_LIBS =\n \tX = .exe\ndiff --git a/compat/win32/poll.c b/compat/win32/poll.c\nnew file mode 100644\nindex 0000000..708a6c9\n--- /dev/null\n+++ b/compat/win32/poll.c\n@@ -0,0 +1,599 @@\n+/* Emulation for poll(2)\n+   Contributed by Paolo Bonzini.\n+\n+   Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.\n+\n+   This file is part of gnulib.\n+\n+   This program is free software; you can redistribute it and/or modify\n+   it under the terms of the GNU General Public License as published by\n+   the Free Software Foundation; either version 2, or (at your option)\n+   any later version.\n+\n+   This program is distributed in the hope that it will be useful,\n+   but WITHOUT ANY WARRANTY; without even the implied warranty of\n+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+   GNU General Public License for more details.\n+\n+   You should have received a copy of the GNU General Public License along\n+   with this program; if not, write to the Free Software Foundation,\n+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */\n+\n+/* Tell gcc not to warn about the (nfd < 0) tests, below.  */\n+#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__\n+# pragma GCC diagnostic ignored \"-Wtype-limits\"\n+#endif\n+\n+#include <malloc.h>\n+\n+#include <sys/types.h>\n+#include \"poll.h\"\n+#include <errno.h>\n+#include <limits.h>\n+#include <assert.h>\n+\n+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__\n+# define WIN32_NATIVE\n+# if defined (_MSC_VER)\n+#  define _WIN32_WINNT 0x0502\n+# endif\n+# include <winsock2.h>\n+# include <windows.h>\n+# include <io.h>\n+# include <stdio.h>\n+# include <conio.h>\n+#else\n+# include <sys/time.h>\n+# include <sys/socket.h>\n+# include <sys/select.h>\n+# include <unistd.h>\n+#endif\n+\n+#ifdef HAVE_SYS_IOCTL_H\n+# include <sys/ioctl.h>\n+#endif\n+#ifdef HAVE_SYS_FILIO_H\n+# include <sys/filio.h>\n+#endif\n+\n+#include <time.h>\n+\n+#ifndef INFTIM\n+# define INFTIM (-1)\n+#endif\n+\n+/* BeOS does not have MSG_PEEK.  */\n+#ifndef MSG_PEEK\n+# define MSG_PEEK 0\n+#endif\n+\n+#ifdef WIN32_NATIVE\n+\n+#define IsConsoleHandle(h) (((long) (h) & 3) == 3)\n+\n+static BOOL\n+IsSocketHandle (HANDLE h)\n+{\n+  WSANETWORKEVENTS ev;\n+\n+  if (IsConsoleHandle (h))\n+    return FALSE;\n+\n+  /* Under Wine, it seems that getsockopt returns 0 for pipes too.\n+     WSAEnumNetworkEvents instead distinguishes the two correctly.  */\n+  ev.lNetworkEvents = 0xDEADBEEF;\n+  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);\n+  return ev.lNetworkEvents != 0xDEADBEEF;\n+}\n+\n+/* Declare data structures for ntdll functions.  */\n+typedef struct _FILE_PIPE_LOCAL_INFORMATION {\n+  ULONG NamedPipeType;\n+  ULONG NamedPipeConfiguration;\n+  ULONG MaximumInstances;\n+  ULONG CurrentInstances;\n+  ULONG InboundQuota;\n+  ULONG ReadDataAvailable;\n+  ULONG OutboundQuota;\n+  ULONG WriteQuotaAvailable;\n+  ULONG NamedPipeState;\n+  ULONG NamedPipeEnd;\n+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;\n+\n+typedef struct _IO_STATUS_BLOCK\n+{\n+  union {\n+    DWORD Status;\n+    PVOID Pointer;\n+  } u;\n+  ULONG_PTR Information;\n+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;\n+\n+typedef enum _FILE_INFORMATION_CLASS {\n+  FilePipeLocalInformation = 24\n+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;\n+\n+typedef DWORD (WINAPI *PNtQueryInformationFile)\n+\t (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);\n+\n+# ifndef PIPE_BUF\n+#  define PIPE_BUF      512\n+# endif\n+\n+/* Compute revents values for file handle H.  If some events cannot happen\n+   for the handle, eliminate them from *P_SOUGHT.  */\n+\n+static int\n+win32_compute_revents (HANDLE h, int *p_sought)\n+{\n+  int i, ret, happened;\n+  INPUT_RECORD *irbuffer;\n+  DWORD avail, nbuffer;\n+  BOOL bRet;\n+  IO_STATUS_BLOCK iosb;\n+  FILE_PIPE_LOCAL_INFORMATION fpli;\n+  static PNtQueryInformationFile NtQueryInformationFile;\n+  static BOOL once_only;\n+\n+  switch (GetFileType (h))\n+    {\n+    case FILE_TYPE_PIPE:\n+      if (!once_only)\n+\t{\n+\t  NtQueryInformationFile = (PNtQueryInformationFile)\n+\t    GetProcAddress (GetModuleHandle (\"ntdll.dll\"),\n+\t\t\t    \"NtQueryInformationFile\");\n+\t  once_only = TRUE;\n+\t}\n+\n+      happened = 0;\n+      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)\n+\t{\n+\t  if (avail)\n+\t    happened |= *p_sought & (POLLIN | POLLRDNORM);\n+\t}\n+      else if (GetLastError () == ERROR_BROKEN_PIPE)\n+\thappened |= POLLHUP;\n+\n+      else\n+\t{\n+\t  /* It was the write-end of the pipe.  Check if it is writable.\n+\t     If NtQueryInformationFile fails, optimistically assume the pipe is\n+\t     writable.  This could happen on Win9x, where NtQueryInformationFile\n+\t     is not available, or if we inherit a pipe that doesn't permit\n+\t     FILE_READ_ATTRIBUTES access on the write end (I think this should\n+\t     not happen since WinXP SP2; WINE seems fine too).  Otherwise,\n+\t     ensure that enough space is available for atomic writes.  */\n+\t  memset (&iosb, 0, sizeof (iosb));\n+\t  memset (&fpli, 0, sizeof (fpli));\n+\n+\t  if (!NtQueryInformationFile\n+\t      || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),\n+\t\t\t\t\t FilePipeLocalInformation)\n+\t      || fpli.WriteQuotaAvailable >= PIPE_BUF\n+\t      || (fpli.OutboundQuota < PIPE_BUF &&\n+\t\t  fpli.WriteQuotaAvailable == fpli.OutboundQuota))\n+\t    happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);\n+\t}\n+      return happened;\n+\n+    case FILE_TYPE_CHAR:\n+      ret = WaitForSingleObject (h, 0);\n+      if (!IsConsoleHandle (h))\n+\treturn ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;\n+\n+      nbuffer = avail = 0;\n+      bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);\n+      if (bRet)\n+\t{\n+\t  /* Input buffer.  */\n+\t  *p_sought &= POLLIN | POLLRDNORM;\n+\t  if (nbuffer == 0)\n+\t    return POLLHUP;\n+\t  if (!*p_sought)\n+\t    return 0;\n+\n+\t  irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));\n+\t  bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);\n+\t  if (!bRet || avail == 0)\n+\t    return POLLHUP;\n+\n+\t  for (i = 0; i < avail; i++)\n+\t    if (irbuffer[i].EventType == KEY_EVENT)\n+\t      return *p_sought;\n+\t  return 0;\n+\t}\n+      else\n+\t{\n+\t  /* Screen buffer.  */\n+\t  *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;\n+\t  return *p_sought;\n+\t}\n+\n+    default:\n+      ret = WaitForSingleObject (h, 0);\n+      if (ret == WAIT_OBJECT_0)\n+\treturn *p_sought & ~(POLLPRI | POLLRDBAND);\n+\n+      return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);\n+    }\n+}\n+\n+/* Convert fd_sets returned by select into revents values.  */\n+\n+static int\n+win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)\n+{\n+  int happened = 0;\n+\n+  if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)\n+    happened |= (POLLIN | POLLRDNORM) & sought;\n+\n+  else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))\n+    {\n+      int r, error;\n+\n+      char data[64];\n+      WSASetLastError (0);\n+      r = recv (h, data, sizeof (data), MSG_PEEK);\n+      error = WSAGetLastError ();\n+      WSASetLastError (0);\n+\n+      if (r > 0 || error == WSAENOTCONN)\n+\thappened |= (POLLIN | POLLRDNORM) & sought;\n+\n+      /* Distinguish hung-up sockets from other errors.  */\n+      else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET\n+\t       || error == WSAECONNABORTED || error == WSAENETRESET)\n+\thappened |= POLLHUP;\n+\n+      else\n+\thappened |= POLLERR;\n+    }\n+\n+  if (lNetworkEvents & (FD_WRITE | FD_CONNECT))\n+    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;\n+\n+  if (lNetworkEvents & FD_OOB)\n+    happened |= (POLLPRI | POLLRDBAND) & sought;\n+\n+  return happened;\n+}\n+\n+#else /* !MinGW */\n+\n+/* Convert select(2) returned fd_sets into poll(2) revents values.  */\n+static int\n+compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)\n+{\n+  int happened = 0;\n+  if (FD_ISSET (fd, rfds))\n+    {\n+      int r;\n+      int socket_errno;\n+\n+# if defined __MACH__ && defined __APPLE__\n+      /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK\n+\t for some kinds of descriptors.  Detect if this descriptor is a\n+\t connected socket, a server socket, or something else using a\n+\t 0-byte recv, and use ioctl(2) to detect POLLHUP.  */\n+      r = recv (fd, NULL, 0, MSG_PEEK);\n+      socket_errno = (r < 0) ? errno : 0;\n+      if (r == 0 || socket_errno == ENOTSOCK)\n+\tioctl (fd, FIONREAD, &r);\n+# else\n+      char data[64];\n+      r = recv (fd, data, sizeof (data), MSG_PEEK);\n+      socket_errno = (r < 0) ? errno : 0;\n+# endif\n+      if (r == 0)\n+\thappened |= POLLHUP;\n+\n+      /* If the event happened on an unconnected server socket,\n+\t that's fine. */\n+      else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))\n+\thappened |= (POLLIN | POLLRDNORM) & sought;\n+\n+      /* Distinguish hung-up sockets from other errors.  */\n+      else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET\n+\t       || socket_errno == ECONNABORTED || socket_errno == ENETRESET)\n+\thappened |= POLLHUP;\n+\n+      else\n+\thappened |= POLLERR;\n+    }\n+\n+  if (FD_ISSET (fd, wfds))\n+    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;\n+\n+  if (FD_ISSET (fd, efds))\n+    happened |= (POLLPRI | POLLRDBAND) & sought;\n+\n+  return happened;\n+}\n+#endif /* !MinGW */\n+\n+int\n+poll (pfd, nfd, timeout)\n+     struct pollfd *pfd;\n+     nfds_t nfd;\n+     int timeout;\n+{\n+#ifndef WIN32_NATIVE\n+  fd_set rfds, wfds, efds;\n+  struct timeval tv;\n+  struct timeval *ptv;\n+  int maxfd, rc;\n+  nfds_t i;\n+\n+# ifdef _SC_OPEN_MAX\n+  static int sc_open_max = -1;\n+\n+  if (nfd < 0\n+      || (nfd > sc_open_max\n+\t  && (sc_open_max != -1\n+\t      || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))\n+    {\n+      errno = EINVAL;\n+      return -1;\n+    }\n+# else /* !_SC_OPEN_MAX */\n+#  ifdef OPEN_MAX\n+  if (nfd < 0 || nfd > OPEN_MAX)\n+    {\n+      errno = EINVAL;\n+      return -1;\n+    }\n+#  endif /* OPEN_MAX -- else, no check is needed */\n+# endif /* !_SC_OPEN_MAX */\n+\n+  /* EFAULT is not necessary to implement, but let's do it in the\n+     simplest case. */\n+  if (!pfd)\n+    {\n+      errno = EFAULT;\n+      return -1;\n+    }\n+\n+  /* convert timeout number into a timeval structure */\n+  if (timeout == 0)\n+    {\n+      ptv = &tv;\n+      ptv->tv_sec = 0;\n+      ptv->tv_usec = 0;\n+    }\n+  else if (timeout > 0)\n+    {\n+      ptv = &tv;\n+      ptv->tv_sec = timeout / 1000;\n+      ptv->tv_usec = (timeout % 1000) * 1000;\n+    }\n+  else if (timeout == INFTIM)\n+    /* wait forever */\n+    ptv = NULL;\n+  else\n+    {\n+      errno = EINVAL;\n+      return -1;\n+    }\n+\n+  /* create fd sets and determine max fd */\n+  maxfd = -1;\n+  FD_ZERO (&rfds);\n+  FD_ZERO (&wfds);\n+  FD_ZERO (&efds);\n+  for (i = 0; i < nfd; i++)\n+    {\n+      if (pfd[i].fd < 0)\n+\tcontinue;\n+\n+      if (pfd[i].events & (POLLIN | POLLRDNORM))\n+\tFD_SET (pfd[i].fd, &rfds);\n+\n+      /* see select(2): \"the only exceptional condition detectable\n+\t is out-of-band data received on a socket\", hence we push\n+\t POLLWRBAND events onto wfds instead of efds. */\n+      if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))\n+\tFD_SET (pfd[i].fd, &wfds);\n+      if (pfd[i].events & (POLLPRI | POLLRDBAND))\n+\tFD_SET (pfd[i].fd, &efds);\n+      if (pfd[i].fd >= maxfd\n+\t  && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI\n+\t\t\t       | POLLRDNORM | POLLRDBAND\n+\t\t\t       | POLLWRNORM | POLLWRBAND)))\n+\t{\n+\t  maxfd = pfd[i].fd;\n+\t  if (maxfd > FD_SETSIZE)\n+\t    {\n+\t      errno = EOVERFLOW;\n+\t      return -1;\n+\t    }\n+\t}\n+    }\n+\n+  /* examine fd sets */\n+  rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);\n+  if (rc < 0)\n+    return rc;\n+\n+  /* establish results */\n+  rc = 0;\n+  for (i = 0; i < nfd; i++)\n+    if (pfd[i].fd < 0)\n+      pfd[i].revents = 0;\n+    else\n+      {\n+\tint happened = compute_revents (pfd[i].fd, pfd[i].events,\n+\t\t\t\t\t&rfds, &wfds, &efds);\n+\tif (happened)\n+\t  {\n+\t    pfd[i].revents = happened;\n+\t    rc++;\n+\t  }\n+      }\n+\n+  return rc;\n+#else\n+  static struct timeval tv0;\n+  static HANDLE hEvent;\n+  WSANETWORKEVENTS ev;\n+  HANDLE h, handle_array[FD_SETSIZE + 2];\n+  DWORD ret, wait_timeout, nhandles;\n+  fd_set rfds, wfds, xfds;\n+  BOOL poll_again;\n+  MSG msg;\n+  int rc = 0;\n+  nfds_t i;\n+\n+  if (nfd < 0 || timeout < -1)\n+    {\n+      errno = EINVAL;\n+      return -1;\n+    }\n+\n+  if (!hEvent)\n+    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);\n+\n+  handle_array[0] = hEvent;\n+  nhandles = 1;\n+  FD_ZERO (&rfds);\n+  FD_ZERO (&wfds);\n+  FD_ZERO (&xfds);\n+\n+  /* Classify socket handles and create fd sets. */\n+  for (i = 0; i < nfd; i++)\n+    {\n+      int sought = pfd[i].events;\n+      pfd[i].revents = 0;\n+      if (pfd[i].fd < 0)\n+\tcontinue;\n+      if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND\n+\t\t      | POLLPRI | POLLRDBAND)))\n+\tcontinue;\n+\n+      h = (HANDLE) _get_osfhandle (pfd[i].fd);\n+      assert (h != NULL);\n+      if (IsSocketHandle (h))\n+\t{\n+\t  int requested = FD_CLOSE;\n+\n+\t  /* see above; socket handles are mapped onto select.  */\n+\t  if (sought & (POLLIN | POLLRDNORM))\n+\t    {\n+\t      requested |= FD_READ | FD_ACCEPT;\n+\t      FD_SET ((SOCKET) h, &rfds);\n+\t    }\n+\t  if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))\n+\t    {\n+\t      requested |= FD_WRITE | FD_CONNECT;\n+\t      FD_SET ((SOCKET) h, &wfds);\n+\t    }\n+\t  if (sought & (POLLPRI | POLLRDBAND))\n+\t    {\n+\t      requested |= FD_OOB;\n+\t      FD_SET ((SOCKET) h, &xfds);\n+\t    }\n+\n+\t  if (requested)\n+\t    WSAEventSelect ((SOCKET) h, hEvent, requested);\n+\t}\n+      else\n+\t{\n+\t  /* Poll now.  If we get an event, do not poll again.  Also,\n+\t     screen buffer handles are waitable, and they'll block until\n+\t     a character is available.  win32_compute_revents eliminates\n+\t     bits for the \"wrong\" direction. */\n+\t  pfd[i].revents = win32_compute_revents (h, &sought);\n+\t  if (sought)\n+\t    handle_array[nhandles++] = h;\n+\t  if (pfd[i].revents)\n+\t    timeout = 0;\n+\t}\n+    }\n+\n+  if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)\n+    {\n+      /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but\n+\t no need to call select again.  */\n+      poll_again = FALSE;\n+      wait_timeout = 0;\n+    }\n+  else\n+    {\n+      poll_again = TRUE;\n+      if (timeout == INFTIM)\n+\twait_timeout = INFINITE;\n+      else\n+\twait_timeout = timeout;\n+    }\n+\n+  for (;;)\n+    {\n+      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,\n+\t\t\t\t       wait_timeout, QS_ALLINPUT);\n+\n+      if (ret == WAIT_OBJECT_0 + nhandles)\n+\t{\n+\t  /* new input of some other kind */\n+\t  BOOL bRet;\n+\t  while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)\n+\t    {\n+\t      TranslateMessage (&msg);\n+\t      DispatchMessage (&msg);\n+\t    }\n+\t}\n+      else\n+\tbreak;\n+    }\n+\n+  if (poll_again)\n+    select (0, &rfds, &wfds, &xfds, &tv0);\n+\n+  /* Place a sentinel at the end of the array.  */\n+  handle_array[nhandles] = NULL;\n+  nhandles = 1;\n+  for (i = 0; i < nfd; i++)\n+    {\n+      int happened;\n+\n+      if (pfd[i].fd < 0)\n+\tcontinue;\n+      if (!(pfd[i].events & (POLLIN | POLLRDNORM |\n+\t\t\t     POLLOUT | POLLWRNORM | POLLWRBAND)))\n+\tcontinue;\n+\n+      h = (HANDLE) _get_osfhandle (pfd[i].fd);\n+      if (h != handle_array[nhandles])\n+\t{\n+\t  /* It's a socket.  */\n+\t  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);\n+\t  WSAEventSelect ((SOCKET) h, 0, 0);\n+\n+\t  /* If we're lucky, WSAEnumNetworkEvents already provided a way\n+\t     to distinguish FD_READ and FD_ACCEPT; this saves a recv later.  */\n+\t  if (FD_ISSET ((SOCKET) h, &rfds)\n+\t      && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))\n+\t    ev.lNetworkEvents |= FD_READ | FD_ACCEPT;\n+\t  if (FD_ISSET ((SOCKET) h, &wfds))\n+\t    ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;\n+\t  if (FD_ISSET ((SOCKET) h, &xfds))\n+\t    ev.lNetworkEvents |= FD_OOB;\n+\n+\t  happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,\n+\t\t\t\t\t\t   ev.lNetworkEvents);\n+\t}\n+      else\n+\t{\n+\t  /* Not a socket.  */\n+\t  int sought = pfd[i].events;\n+\t  happened = win32_compute_revents (h, &sought);\n+\t  nhandles++;\n+\t}\n+\n+       if ((pfd[i].revents |= happened) != 0)\n+\trc++;\n+    }\n+\n+  return rc;\n+#endif\n+}\ndiff --git a/compat/win32/poll.h b/compat/win32/poll.h\nnew file mode 100644\nindex 0000000..b7aa59d\n--- /dev/null\n+++ b/compat/win32/poll.h\n@@ -0,0 +1,53 @@\n+/* Header for poll(2) emulation\n+   Contributed by Paolo Bonzini.\n+\n+   Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.\n+\n+   This file is part of gnulib.\n+\n+   This program is free software; you can redistribute it and/or modify\n+   it under the terms of the GNU General Public License as published by\n+   the Free Software Foundation; either version 2, or (at your option)\n+   any later version.\n+\n+   This program is distributed in the hope that it will be useful,\n+   but WITHOUT ANY WARRANTY; without even the implied warranty of\n+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+   GNU General Public License for more details.\n+\n+   You should have received a copy of the GNU General Public License along\n+   with this program; if not, write to the Free Software Foundation,\n+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */\n+\n+#ifndef _GL_POLL_H\n+#define _GL_POLL_H\n+\n+/* fake a poll(2) environment */\n+#define POLLIN      0x0001      /* any readable data available   */\n+#define POLLPRI     0x0002      /* OOB/Urgent readable data      */\n+#define POLLOUT     0x0004      /* file descriptor is writeable  */\n+#define POLLERR     0x0008      /* some poll error occurred      */\n+#define POLLHUP     0x0010      /* file descriptor was \"hung up\" */\n+#define POLLNVAL    0x0020      /* requested events \"invalid\"    */\n+#define POLLRDNORM  0x0040\n+#define POLLRDBAND  0x0080\n+#define POLLWRNORM  0x0100\n+#define POLLWRBAND  0x0200\n+\n+struct pollfd\n+{\n+  int fd;                       /* which file descriptor to poll */\n+  short events;                 /* events we are interested in   */\n+  short revents;                /* events found on return        */\n+};\n+\n+typedef unsigned long nfds_t;\n+\n+extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);\n+\n+/* Define INFTIM only if doing so conforms to POSIX.  */\n+#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)\n+#define INFTIM (-1)\n+#endif\n+\n+#endif /* _GL_POLL_H */\ndiff --git a/compat/win32/sys/poll.c b/compat/win32/sys/poll.c\ndeleted file mode 100644\nindex 708a6c9..0000000\n--- a/compat/win32/sys/poll.c\n+++ /dev/null\n@@ -1,599 +0,0 @@\n-/* Emulation for poll(2)\n-   Contributed by Paolo Bonzini.\n-\n-   Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.\n-\n-   This file is part of gnulib.\n-\n-   This program is free software; you can redistribute it and/or modify\n-   it under the terms of the GNU General Public License as published by\n-   the Free Software Foundation; either version 2, or (at your option)\n-   any later version.\n-\n-   This program is distributed in the hope that it will be useful,\n-   but WITHOUT ANY WARRANTY; without even the implied warranty of\n-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n-   GNU General Public License for more details.\n-\n-   You should have received a copy of the GNU General Public License along\n-   with this program; if not, write to the Free Software Foundation,\n-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */\n-\n-/* Tell gcc not to warn about the (nfd < 0) tests, below.  */\n-#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__\n-# pragma GCC diagnostic ignored \"-Wtype-limits\"\n-#endif\n-\n-#include <malloc.h>\n-\n-#include <sys/types.h>\n-#include \"poll.h\"\n-#include <errno.h>\n-#include <limits.h>\n-#include <assert.h>\n-\n-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__\n-# define WIN32_NATIVE\n-# if defined (_MSC_VER)\n-#  define _WIN32_WINNT 0x0502\n-# endif\n-# include <winsock2.h>\n-# include <windows.h>\n-# include <io.h>\n-# include <stdio.h>\n-# include <conio.h>\n-#else\n-# include <sys/time.h>\n-# include <sys/socket.h>\n-# include <sys/select.h>\n-# include <unistd.h>\n-#endif\n-\n-#ifdef HAVE_SYS_IOCTL_H\n-# include <sys/ioctl.h>\n-#endif\n-#ifdef HAVE_SYS_FILIO_H\n-# include <sys/filio.h>\n-#endif\n-\n-#include <time.h>\n-\n-#ifndef INFTIM\n-# define INFTIM (-1)\n-#endif\n-\n-/* BeOS does not have MSG_PEEK.  */\n-#ifndef MSG_PEEK\n-# define MSG_PEEK 0\n-#endif\n-\n-#ifdef WIN32_NATIVE\n-\n-#define IsConsoleHandle(h) (((long) (h) & 3) == 3)\n-\n-static BOOL\n-IsSocketHandle (HANDLE h)\n-{\n-  WSANETWORKEVENTS ev;\n-\n-  if (IsConsoleHandle (h))\n-    return FALSE;\n-\n-  /* Under Wine, it seems that getsockopt returns 0 for pipes too.\n-     WSAEnumNetworkEvents instead distinguishes the two correctly.  */\n-  ev.lNetworkEvents = 0xDEADBEEF;\n-  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);\n-  return ev.lNetworkEvents != 0xDEADBEEF;\n-}\n-\n-/* Declare data structures for ntdll functions.  */\n-typedef struct _FILE_PIPE_LOCAL_INFORMATION {\n-  ULONG NamedPipeType;\n-  ULONG NamedPipeConfiguration;\n-  ULONG MaximumInstances;\n-  ULONG CurrentInstances;\n-  ULONG InboundQuota;\n-  ULONG ReadDataAvailable;\n-  ULONG OutboundQuota;\n-  ULONG WriteQuotaAvailable;\n-  ULONG NamedPipeState;\n-  ULONG NamedPipeEnd;\n-} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;\n-\n-typedef struct _IO_STATUS_BLOCK\n-{\n-  union {\n-    DWORD Status;\n-    PVOID Pointer;\n-  } u;\n-  ULONG_PTR Information;\n-} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;\n-\n-typedef enum _FILE_INFORMATION_CLASS {\n-  FilePipeLocalInformation = 24\n-} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;\n-\n-typedef DWORD (WINAPI *PNtQueryInformationFile)\n-\t (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);\n-\n-# ifndef PIPE_BUF\n-#  define PIPE_BUF      512\n-# endif\n-\n-/* Compute revents values for file handle H.  If some events cannot happen\n-   for the handle, eliminate them from *P_SOUGHT.  */\n-\n-static int\n-win32_compute_revents (HANDLE h, int *p_sought)\n-{\n-  int i, ret, happened;\n-  INPUT_RECORD *irbuffer;\n-  DWORD avail, nbuffer;\n-  BOOL bRet;\n-  IO_STATUS_BLOCK iosb;\n-  FILE_PIPE_LOCAL_INFORMATION fpli;\n-  static PNtQueryInformationFile NtQueryInformationFile;\n-  static BOOL once_only;\n-\n-  switch (GetFileType (h))\n-    {\n-    case FILE_TYPE_PIPE:\n-      if (!once_only)\n-\t{\n-\t  NtQueryInformationFile = (PNtQueryInformationFile)\n-\t    GetProcAddress (GetModuleHandle (\"ntdll.dll\"),\n-\t\t\t    \"NtQueryInformationFile\");\n-\t  once_only = TRUE;\n-\t}\n-\n-      happened = 0;\n-      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)\n-\t{\n-\t  if (avail)\n-\t    happened |= *p_sought & (POLLIN | POLLRDNORM);\n-\t}\n-      else if (GetLastError () == ERROR_BROKEN_PIPE)\n-\thappened |= POLLHUP;\n-\n-      else\n-\t{\n-\t  /* It was the write-end of the pipe.  Check if it is writable.\n-\t     If NtQueryInformationFile fails, optimistically assume the pipe is\n-\t     writable.  This could happen on Win9x, where NtQueryInformationFile\n-\t     is not available, or if we inherit a pipe that doesn't permit\n-\t     FILE_READ_ATTRIBUTES access on the write end (I think this should\n-\t     not happen since WinXP SP2; WINE seems fine too).  Otherwise,\n-\t     ensure that enough space is available for atomic writes.  */\n-\t  memset (&iosb, 0, sizeof (iosb));\n-\t  memset (&fpli, 0, sizeof (fpli));\n-\n-\t  if (!NtQueryInformationFile\n-\t      || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),\n-\t\t\t\t\t FilePipeLocalInformation)\n-\t      || fpli.WriteQuotaAvailable >= PIPE_BUF\n-\t      || (fpli.OutboundQuota < PIPE_BUF &&\n-\t\t  fpli.WriteQuotaAvailable == fpli.OutboundQuota))\n-\t    happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);\n-\t}\n-      return happened;\n-\n-    case FILE_TYPE_CHAR:\n-      ret = WaitForSingleObject (h, 0);\n-      if (!IsConsoleHandle (h))\n-\treturn ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;\n-\n-      nbuffer = avail = 0;\n-      bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);\n-      if (bRet)\n-\t{\n-\t  /* Input buffer.  */\n-\t  *p_sought &= POLLIN | POLLRDNORM;\n-\t  if (nbuffer == 0)\n-\t    return POLLHUP;\n-\t  if (!*p_sought)\n-\t    return 0;\n-\n-\t  irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));\n-\t  bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);\n-\t  if (!bRet || avail == 0)\n-\t    return POLLHUP;\n-\n-\t  for (i = 0; i < avail; i++)\n-\t    if (irbuffer[i].EventType == KEY_EVENT)\n-\t      return *p_sought;\n-\t  return 0;\n-\t}\n-      else\n-\t{\n-\t  /* Screen buffer.  */\n-\t  *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;\n-\t  return *p_sought;\n-\t}\n-\n-    default:\n-      ret = WaitForSingleObject (h, 0);\n-      if (ret == WAIT_OBJECT_0)\n-\treturn *p_sought & ~(POLLPRI | POLLRDBAND);\n-\n-      return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);\n-    }\n-}\n-\n-/* Convert fd_sets returned by select into revents values.  */\n-\n-static int\n-win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)\n-{\n-  int happened = 0;\n-\n-  if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)\n-    happened |= (POLLIN | POLLRDNORM) & sought;\n-\n-  else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))\n-    {\n-      int r, error;\n-\n-      char data[64];\n-      WSASetLastError (0);\n-      r = recv (h, data, sizeof (data), MSG_PEEK);\n-      error = WSAGetLastError ();\n-      WSASetLastError (0);\n-\n-      if (r > 0 || error == WSAENOTCONN)\n-\thappened |= (POLLIN | POLLRDNORM) & sought;\n-\n-      /* Distinguish hung-up sockets from other errors.  */\n-      else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET\n-\t       || error == WSAECONNABORTED || error == WSAENETRESET)\n-\thappened |= POLLHUP;\n-\n-      else\n-\thappened |= POLLERR;\n-    }\n-\n-  if (lNetworkEvents & (FD_WRITE | FD_CONNECT))\n-    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;\n-\n-  if (lNetworkEvents & FD_OOB)\n-    happened |= (POLLPRI | POLLRDBAND) & sought;\n-\n-  return happened;\n-}\n-\n-#else /* !MinGW */\n-\n-/* Convert select(2) returned fd_sets into poll(2) revents values.  */\n-static int\n-compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)\n-{\n-  int happened = 0;\n-  if (FD_ISSET (fd, rfds))\n-    {\n-      int r;\n-      int socket_errno;\n-\n-# if defined __MACH__ && defined __APPLE__\n-      /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK\n-\t for some kinds of descriptors.  Detect if this descriptor is a\n-\t connected socket, a server socket, or something else using a\n-\t 0-byte recv, and use ioctl(2) to detect POLLHUP.  */\n-      r = recv (fd, NULL, 0, MSG_PEEK);\n-      socket_errno = (r < 0) ? errno : 0;\n-      if (r == 0 || socket_errno == ENOTSOCK)\n-\tioctl (fd, FIONREAD, &r);\n-# else\n-      char data[64];\n-      r = recv (fd, data, sizeof (data), MSG_PEEK);\n-      socket_errno = (r < 0) ? errno : 0;\n-# endif\n-      if (r == 0)\n-\thappened |= POLLHUP;\n-\n-      /* If the event happened on an unconnected server socket,\n-\t that's fine. */\n-      else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))\n-\thappened |= (POLLIN | POLLRDNORM) & sought;\n-\n-      /* Distinguish hung-up sockets from other errors.  */\n-      else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET\n-\t       || socket_errno == ECONNABORTED || socket_errno == ENETRESET)\n-\thappened |= POLLHUP;\n-\n-      else\n-\thappened |= POLLERR;\n-    }\n-\n-  if (FD_ISSET (fd, wfds))\n-    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;\n-\n-  if (FD_ISSET (fd, efds))\n-    happened |= (POLLPRI | POLLRDBAND) & sought;\n-\n-  return happened;\n-}\n-#endif /* !MinGW */\n-\n-int\n-poll (pfd, nfd, timeout)\n-     struct pollfd *pfd;\n-     nfds_t nfd;\n-     int timeout;\n-{\n-#ifndef WIN32_NATIVE\n-  fd_set rfds, wfds, efds;\n-  struct timeval tv;\n-  struct timeval *ptv;\n-  int maxfd, rc;\n-  nfds_t i;\n-\n-# ifdef _SC_OPEN_MAX\n-  static int sc_open_max = -1;\n-\n-  if (nfd < 0\n-      || (nfd > sc_open_max\n-\t  && (sc_open_max != -1\n-\t      || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))\n-    {\n-      errno = EINVAL;\n-      return -1;\n-    }\n-# else /* !_SC_OPEN_MAX */\n-#  ifdef OPEN_MAX\n-  if (nfd < 0 || nfd > OPEN_MAX)\n-    {\n-      errno = EINVAL;\n-      return -1;\n-    }\n-#  endif /* OPEN_MAX -- else, no check is needed */\n-# endif /* !_SC_OPEN_MAX */\n-\n-  /* EFAULT is not necessary to implement, but let's do it in the\n-     simplest case. */\n-  if (!pfd)\n-    {\n-      errno = EFAULT;\n-      return -1;\n-    }\n-\n-  /* convert timeout number into a timeval structure */\n-  if (timeout == 0)\n-    {\n-      ptv = &tv;\n-      ptv->tv_sec = 0;\n-      ptv->tv_usec = 0;\n-    }\n-  else if (timeout > 0)\n-    {\n-      ptv = &tv;\n-      ptv->tv_sec = timeout / 1000;\n-      ptv->tv_usec = (timeout % 1000) * 1000;\n-    }\n-  else if (timeout == INFTIM)\n-    /* wait forever */\n-    ptv = NULL;\n-  else\n-    {\n-      errno = EINVAL;\n-      return -1;\n-    }\n-\n-  /* create fd sets and determine max fd */\n-  maxfd = -1;\n-  FD_ZERO (&rfds);\n-  FD_ZERO (&wfds);\n-  FD_ZERO (&efds);\n-  for (i = 0; i < nfd; i++)\n-    {\n-      if (pfd[i].fd < 0)\n-\tcontinue;\n-\n-      if (pfd[i].events & (POLLIN | POLLRDNORM))\n-\tFD_SET (pfd[i].fd, &rfds);\n-\n-      /* see select(2): \"the only exceptional condition detectable\n-\t is out-of-band data received on a socket\", hence we push\n-\t POLLWRBAND events onto wfds instead of efds. */\n-      if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))\n-\tFD_SET (pfd[i].fd, &wfds);\n-      if (pfd[i].events & (POLLPRI | POLLRDBAND))\n-\tFD_SET (pfd[i].fd, &efds);\n-      if (pfd[i].fd >= maxfd\n-\t  && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI\n-\t\t\t       | POLLRDNORM | POLLRDBAND\n-\t\t\t       | POLLWRNORM | POLLWRBAND)))\n-\t{\n-\t  maxfd = pfd[i].fd;\n-\t  if (maxfd > FD_SETSIZE)\n-\t    {\n-\t      errno = EOVERFLOW;\n-\t      return -1;\n-\t    }\n-\t}\n-    }\n-\n-  /* examine fd sets */\n-  rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);\n-  if (rc < 0)\n-    return rc;\n-\n-  /* establish results */\n-  rc = 0;\n-  for (i = 0; i < nfd; i++)\n-    if (pfd[i].fd < 0)\n-      pfd[i].revents = 0;\n-    else\n-      {\n-\tint happened = compute_revents (pfd[i].fd, pfd[i].events,\n-\t\t\t\t\t&rfds, &wfds, &efds);\n-\tif (happened)\n-\t  {\n-\t    pfd[i].revents = happened;\n-\t    rc++;\n-\t  }\n-      }\n-\n-  return rc;\n-#else\n-  static struct timeval tv0;\n-  static HANDLE hEvent;\n-  WSANETWORKEVENTS ev;\n-  HANDLE h, handle_array[FD_SETSIZE + 2];\n-  DWORD ret, wait_timeout, nhandles;\n-  fd_set rfds, wfds, xfds;\n-  BOOL poll_again;\n-  MSG msg;\n-  int rc = 0;\n-  nfds_t i;\n-\n-  if (nfd < 0 || timeout < -1)\n-    {\n-      errno = EINVAL;\n-      return -1;\n-    }\n-\n-  if (!hEvent)\n-    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);\n-\n-  handle_array[0] = hEvent;\n-  nhandles = 1;\n-  FD_ZERO (&rfds);\n-  FD_ZERO (&wfds);\n-  FD_ZERO (&xfds);\n-\n-  /* Classify socket handles and create fd sets. */\n-  for (i = 0; i < nfd; i++)\n-    {\n-      int sought = pfd[i].events;\n-      pfd[i].revents = 0;\n-      if (pfd[i].fd < 0)\n-\tcontinue;\n-      if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND\n-\t\t      | POLLPRI | POLLRDBAND)))\n-\tcontinue;\n-\n-      h = (HANDLE) _get_osfhandle (pfd[i].fd);\n-      assert (h != NULL);\n-      if (IsSocketHandle (h))\n-\t{\n-\t  int requested = FD_CLOSE;\n-\n-\t  /* see above; socket handles are mapped onto select.  */\n-\t  if (sought & (POLLIN | POLLRDNORM))\n-\t    {\n-\t      requested |= FD_READ | FD_ACCEPT;\n-\t      FD_SET ((SOCKET) h, &rfds);\n-\t    }\n-\t  if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))\n-\t    {\n-\t      requested |= FD_WRITE | FD_CONNECT;\n-\t      FD_SET ((SOCKET) h, &wfds);\n-\t    }\n-\t  if (sought & (POLLPRI | POLLRDBAND))\n-\t    {\n-\t      requested |= FD_OOB;\n-\t      FD_SET ((SOCKET) h, &xfds);\n-\t    }\n-\n-\t  if (requested)\n-\t    WSAEventSelect ((SOCKET) h, hEvent, requested);\n-\t}\n-      else\n-\t{\n-\t  /* Poll now.  If we get an event, do not poll again.  Also,\n-\t     screen buffer handles are waitable, and they'll block until\n-\t     a character is available.  win32_compute_revents eliminates\n-\t     bits for the \"wrong\" direction. */\n-\t  pfd[i].revents = win32_compute_revents (h, &sought);\n-\t  if (sought)\n-\t    handle_array[nhandles++] = h;\n-\t  if (pfd[i].revents)\n-\t    timeout = 0;\n-\t}\n-    }\n-\n-  if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)\n-    {\n-      /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but\n-\t no need to call select again.  */\n-      poll_again = FALSE;\n-      wait_timeout = 0;\n-    }\n-  else\n-    {\n-      poll_again = TRUE;\n-      if (timeout == INFTIM)\n-\twait_timeout = INFINITE;\n-      else\n-\twait_timeout = timeout;\n-    }\n-\n-  for (;;)\n-    {\n-      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,\n-\t\t\t\t       wait_timeout, QS_ALLINPUT);\n-\n-      if (ret == WAIT_OBJECT_0 + nhandles)\n-\t{\n-\t  /* new input of some other kind */\n-\t  BOOL bRet;\n-\t  while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)\n-\t    {\n-\t      TranslateMessage (&msg);\n-\t      DispatchMessage (&msg);\n-\t    }\n-\t}\n-      else\n-\tbreak;\n-    }\n-\n-  if (poll_again)\n-    select (0, &rfds, &wfds, &xfds, &tv0);\n-\n-  /* Place a sentinel at the end of the array.  */\n-  handle_array[nhandles] = NULL;\n-  nhandles = 1;\n-  for (i = 0; i < nfd; i++)\n-    {\n-      int happened;\n-\n-      if (pfd[i].fd < 0)\n-\tcontinue;\n-      if (!(pfd[i].events & (POLLIN | POLLRDNORM |\n-\t\t\t     POLLOUT | POLLWRNORM | POLLWRBAND)))\n-\tcontinue;\n-\n-      h = (HANDLE) _get_osfhandle (pfd[i].fd);\n-      if (h != handle_array[nhandles])\n-\t{\n-\t  /* It's a socket.  */\n-\t  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);\n-\t  WSAEventSelect ((SOCKET) h, 0, 0);\n-\n-\t  /* If we're lucky, WSAEnumNetworkEvents already provided a way\n-\t     to distinguish FD_READ and FD_ACCEPT; this saves a recv later.  */\n-\t  if (FD_ISSET ((SOCKET) h, &rfds)\n-\t      && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))\n-\t    ev.lNetworkEvents |= FD_READ | FD_ACCEPT;\n-\t  if (FD_ISSET ((SOCKET) h, &wfds))\n-\t    ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;\n-\t  if (FD_ISSET ((SOCKET) h, &xfds))\n-\t    ev.lNetworkEvents |= FD_OOB;\n-\n-\t  happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,\n-\t\t\t\t\t\t   ev.lNetworkEvents);\n-\t}\n-      else\n-\t{\n-\t  /* Not a socket.  */\n-\t  int sought = pfd[i].events;\n-\t  happened = win32_compute_revents (h, &sought);\n-\t  nhandles++;\n-\t}\n-\n-       if ((pfd[i].revents |= happened) != 0)\n-\trc++;\n-    }\n-\n-  return rc;\n-#endif\n-}\ndiff --git a/compat/win32/sys/poll.h b/compat/win32/sys/poll.h\ndeleted file mode 100644\nindex b7aa59d..0000000\n--- a/compat/win32/sys/poll.h\n+++ /dev/null\n@@ -1,53 +0,0 @@\n-/* Header for poll(2) emulation\n-   Contributed by Paolo Bonzini.\n-\n-   Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.\n-\n-   This file is part of gnulib.\n-\n-   This program is free software; you can redistribute it and/or modify\n-   it under the terms of the GNU General Public License as published by\n-   the Free Software Foundation; either version 2, or (at your option)\n-   any later version.\n-\n-   This program is distributed in the hope that it will be useful,\n-   but WITHOUT ANY WARRANTY; without even the implied warranty of\n-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n-   GNU General Public License for more details.\n-\n-   You should have received a copy of the GNU General Public License along\n-   with this program; if not, write to the Free Software Foundation,\n-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */\n-\n-#ifndef _GL_POLL_H\n-#define _GL_POLL_H\n-\n-/* fake a poll(2) environment */\n-#define POLLIN      0x0001      /* any readable data available   */\n-#define POLLPRI     0x0002      /* OOB/Urgent readable data      */\n-#define POLLOUT     0x0004      /* file descriptor is writeable  */\n-#define POLLERR     0x0008      /* some poll error occurred      */\n-#define POLLHUP     0x0010      /* file descriptor was \"hung up\" */\n-#define POLLNVAL    0x0020      /* requested events \"invalid\"    */\n-#define POLLRDNORM  0x0040\n-#define POLLRDBAND  0x0080\n-#define POLLWRNORM  0x0100\n-#define POLLWRBAND  0x0200\n-\n-struct pollfd\n-{\n-  int fd;                       /* which file descriptor to poll */\n-  short events;                 /* events we are interested in   */\n-  short revents;                /* events found on return        */\n-};\n-\n-typedef unsigned long nfds_t;\n-\n-extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);\n-\n-/* Define INFTIM only if doing so conforms to POSIX.  */\n-#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)\n-#define INFTIM (-1)\n-#endif\n-\n-#endif /* _GL_POLL_H */\n-- \n1.7.7.msysgit.1.1.g7b316\n"},{"id":"178239","messageId":"1319472131-3968-3-git-send-email-kusmabite@gmail.com","threadId":"28759","inReplyTo":"1319472131-3968-1-git-send-email-kusmabite@gmail.com","subject":"[PATCH v4 2/3] compat/win32/poll.c: upgrade from upstream","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-10-24T16:02:10Z","receivedAt":"2011-10-24T16:02:10Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"poll.c is updated from revision adc3a5b in\ngit://git.savannah.gnu.org/gnulib.git\n\nThe changes are applied with --whitespace=fix to reduce noise.\n\npoll.h is not upgraded, because the most recent version now\ncontains template-stuff that breaks compilation for us.\n\nSigned-off-by: Erik Faye-Lund <kusmabite@gmail.com>\n---\n compat/win32/poll.c |   19 +++++++++++++------\n 1 files changed, 13 insertions(+), 6 deletions(-)\n\ndiff --git a/compat/win32/poll.c b/compat/win32/poll.c\nindex 708a6c9..403eaa7 100644\n--- a/compat/win32/poll.c\n+++ b/compat/win32/poll.c\n@@ -1,7 +1,7 @@\n /* Emulation for poll(2)\n    Contributed by Paolo Bonzini.\n \n-   Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.\n+   Copyright 2001-2003, 2006-2011 Free Software Foundation, Inc.\n \n    This file is part of gnulib.\n \n@@ -27,7 +27,10 @@\n #include <malloc.h>\n \n #include <sys/types.h>\n-#include \"poll.h\"\n+\n+/* Specification.  */\n+#include <poll.h>\n+\n #include <errno.h>\n #include <limits.h>\n #include <assert.h>\n@@ -314,10 +317,7 @@ compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)\n #endif /* !MinGW */\n \n int\n-poll (pfd, nfd, timeout)\n-     struct pollfd *pfd;\n-     nfds_t nfd;\n-     int timeout;\n+poll (struct pollfd *pfd, nfds_t nfd, int timeout)\n {\n #ifndef WIN32_NATIVE\n   fd_set rfds, wfds, efds;\n@@ -454,6 +454,7 @@ poll (pfd, nfd, timeout)\n   if (!hEvent)\n     hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);\n \n+restart:\n   handle_array[0] = hEvent;\n   nhandles = 1;\n   FD_ZERO (&rfds);\n@@ -594,6 +595,12 @@ poll (pfd, nfd, timeout)\n \trc++;\n     }\n \n+  if (!rc && timeout == INFTIM)\n+    {\n+      SwitchToThread();\n+      goto restart;\n+    }\n+\n   return rc;\n #endif\n }\n-- \n1.7.7.msysgit.1.1.g7b316\n"},{"id":"178240","messageId":"1319472131-3968-4-git-send-email-kusmabite@gmail.com","threadId":"28759","inReplyTo":"1319472131-3968-1-git-send-email-kusmabite@gmail.com","subject":"[PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-10-24T16:02:11Z","receivedAt":"2011-10-24T16:02:11Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"The POSIX-function fork is not supported on Windows. Use our\nstart_command API instead.\n\nAs this is the last call-site that depends on the fork-stub in\ncompat/mingw.h, remove that as well.\n\nAdd an undocumented flag to git-archive that tells it that the\naction originated from a remote, so features can be disabled.\nThanks to Jeff King for work on this part.\n\nRemove the NOT_MINGW-prereq for t5000, as git-archive --remote\nnow works.\n\nSigned-off-by: Erik Faye-Lund <kusmabite@gmail.com>\nHelped-by: Jeff King <peff@peff.net>\n---\n builtin/archive.c        |    6 +++-\n builtin/upload-archive.c |   68 ++++++++++++++-------------------------------\n compat/mingw.h           |    2 -\n t/t5000-tar-tree.sh      |   10 +++---\n 4 files changed, 31 insertions(+), 55 deletions(-)\n\ndiff --git a/builtin/archive.c b/builtin/archive.c\nindex 931956d..e405566 100644\n--- a/builtin/archive.c\n+++ b/builtin/archive.c\n@@ -87,6 +87,7 @@ int cmd_archive(int argc, const char **argv, const char *prefix)\n \tconst char *exec = \"git-upload-archive\";\n \tconst char *output = NULL;\n \tconst char *remote = NULL;\n+\tint is_remote = 0;\n \tstruct option local_opts[] = {\n \t\tOPT_STRING('o', \"output\", &output, \"file\",\n \t\t\t\"write the archive to this file\"),\n@@ -94,6 +95,9 @@ int cmd_archive(int argc, const char **argv, const char *prefix)\n \t\t\t\"retrieve the archive from remote repository <repo>\"),\n \t\tOPT_STRING(0, \"exec\", &exec, \"cmd\",\n \t\t\t\"path to the remote git-upload-archive command\"),\n+\t\t{ OPTION_BOOLEAN, 0, \"remote-request\", &is_remote, NULL,\n+\t\t\t\"indicate we are serving a remote request\",\n+\t\t\tPARSE_OPT_NOARG | PARSE_OPT_HIDDEN },\n \t\tOPT_END()\n \t};\n \n@@ -108,5 +112,5 @@ int cmd_archive(int argc, const char **argv, const char *prefix)\n \n \tsetvbuf(stderr, NULL, _IOLBF, BUFSIZ);\n \n-\treturn write_archive(argc, argv, prefix, 1, output, 0);\n+\treturn write_archive(argc, argv, prefix, 1, output, is_remote);\n }\ndiff --git a/builtin/upload-archive.c b/builtin/upload-archive.c\nindex 2d0b383..c57e8bd 100644\n--- a/builtin/upload-archive.c\n+++ b/builtin/upload-archive.c\n@@ -6,6 +6,7 @@\n #include \"archive.h\"\n #include \"pkt-line.h\"\n #include \"sideband.h\"\n+#include \"run-command.h\"\n \n static const char upload_archive_usage[] =\n \t\"git upload-archive <repo>\";\n@@ -18,28 +19,17 @@ static const char lostchild[] =\n \n #define MAX_ARGS (64)\n \n-static int run_upload_archive(int argc, const char **argv, const char *prefix)\n+static void prepare_argv(const char **sent_argv, const char **argv)\n {\n-\tconst char *sent_argv[MAX_ARGS];\n \tconst char *arg_cmd = \"argument \";\n \tchar *p, buf[4096];\n \tint sent_argc;\n \tint len;\n \n-\tif (argc != 2)\n-\t\tusage(upload_archive_usage);\n-\n-\tif (strlen(argv[1]) + 1 > sizeof(buf))\n-\t\tdie(\"insanely long repository name\");\n-\n-\tstrcpy(buf, argv[1]); /* enter-repo smudges its argument */\n-\n-\tif (!enter_repo(buf, 0))\n-\t\tdie(\"'%s' does not appear to be a git repository\", buf);\n-\n \t/* put received options in sent_argv[] */\n-\tsent_argc = 1;\n-\tsent_argv[0] = \"git-upload-archive\";\n+\tsent_argc = 2;\n+\tsent_argv[0] = \"archive\";\n+\tsent_argv[1] = \"--remote-request\";\n \tfor (p = buf;;) {\n \t\t/* This will die if not enough free space in buf */\n \t\tlen = packet_read_line(0, p, (buf + sizeof buf) - p);\n@@ -62,9 +52,6 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix)\n \t\t*p++ = 0;\n \t}\n \tsent_argv[sent_argc] = NULL;\n-\n-\t/* parse all options sent by the client */\n-\treturn write_archive(sent_argc, sent_argv, prefix, 0, NULL, 1);\n }\n \n __attribute__((format (printf, 1, 2)))\n@@ -96,38 +83,25 @@ static ssize_t process_input(int child_fd, int band)\n \n int cmd_upload_archive(int argc, const char **argv, const char *prefix)\n {\n-\tpid_t writer;\n-\tint fd1[2], fd2[2];\n-\t/*\n-\t * Set up sideband subprocess.\n-\t *\n-\t * We (parent) monitor and read from child, sending its fd#1 and fd#2\n-\t * multiplexed out to our fd#1.  If the child dies, we tell the other\n-\t * end over channel #3.\n-\t */\n-\tif (pipe(fd1) < 0 || pipe(fd2) < 0) {\n-\t\tint err = errno;\n-\t\tpacket_write(1, \"NACK pipe failed on the remote side\\n\");\n-\t\tdie(\"upload-archive: %s\", strerror(err));\n-\t}\n-\twriter = fork();\n-\tif (writer < 0) {\n+\tconst char *sent_argv[MAX_ARGS];\n+\tstruct child_process cld = { sent_argv };\n+\tcld.out = cld.err = -1;\n+\tcld.git_cmd = 1;\n+\n+\tif (argc != 2)\n+\t\tusage(upload_archive_usage);\n+\n+\tif (!enter_repo(argv[1], 0))\n+\t\tdie(\"'%s' does not appear to be a git repository\", argv[1]);\n+\n+\tprepare_argv(sent_argv, argv);\n+\tif (start_command(&cld)) {\n \t\tint err = errno;\n \t\tpacket_write(1, \"NACK fork failed on the remote side\\n\");\n \t\tdie(\"upload-archive: %s\", strerror(err));\n \t}\n-\tif (!writer) {\n-\t\t/* child - connect fd#1 and fd#2 to the pipe */\n-\t\tdup2(fd1[1], 1);\n-\t\tdup2(fd2[1], 2);\n-\t\tclose(fd1[1]); close(fd2[1]);\n-\t\tclose(fd1[0]); close(fd2[0]); /* we do not read from pipe */\n-\n-\t\texit(run_upload_archive(argc, argv, prefix));\n-\t}\n \n \t/* parent - read from child, multiplex and send out to fd#1 */\n-\tclose(fd1[1]); close(fd2[1]); /* we do not write to pipe */\n \tpacket_write(1, \"ACK\\n\");\n \tpacket_flush(1);\n \n@@ -135,9 +109,9 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)\n \t\tstruct pollfd pfd[2];\n \t\tint status;\n \n-\t\tpfd[0].fd = fd1[0];\n+\t\tpfd[0].fd = cld.out;\n \t\tpfd[0].events = POLLIN;\n-\t\tpfd[1].fd = fd2[0];\n+\t\tpfd[1].fd = cld.err;\n \t\tpfd[1].events = POLLIN;\n \t\tif (poll(pfd, 2, -1) < 0) {\n \t\t\tif (errno != EINTR) {\n@@ -156,7 +130,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)\n \t\t\tif (process_input(pfd[0].fd, 1))\n \t\t\t\tcontinue;\n \n-\t\tif (waitpid(writer, &status, 0) < 0)\n+\t\tif (waitpid(cld.pid, &status, 0) < 0)\n \t\t\terror_clnt(\"%s\", lostchild);\n \t\telse if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)\n \t\t\terror_clnt(\"%s\", deadchild);\ndiff --git a/compat/mingw.h b/compat/mingw.h\nindex fecf0d0..dfb0e87 100644\n--- a/compat/mingw.h\n+++ b/compat/mingw.h\n@@ -85,8 +85,6 @@ static inline int symlink(const char *oldpath, const char *newpath)\n { errno = ENOSYS; return -1; }\n static inline int fchmod(int fildes, mode_t mode)\n { errno = ENOSYS; return -1; }\n-static inline pid_t fork(void)\n-{ errno = ENOSYS; return -1; }\n static inline unsigned int alarm(unsigned int seconds)\n { return 0; }\n static inline int fsync(int fd)\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex d906898..889842e 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -96,7 +96,7 @@ test_expect_success 'git archive with --output' \\\n     'git archive --output=b4.tar HEAD &&\n     test_cmp b.tar b4.tar'\n \n-test_expect_success NOT_MINGW 'git archive --remote' \\\n+test_expect_success 'git archive --remote' \\\n     'git archive --remote=. HEAD >b5.tar &&\n     test_cmp b.tar b5.tar'\n \n@@ -266,7 +266,7 @@ test_expect_success 'archive --list mentions user filter' '\n \tgrep \"^bar\\$\" output\n '\n \n-test_expect_success NOT_MINGW 'archive --list shows only enabled remote filters' '\n+test_expect_success 'archive --list shows only enabled remote filters' '\n \tgit archive --list --remote=. >output &&\n \t! grep \"^tar\\.foo\\$\" output &&\n \tgrep \"^bar\\$\" output\n@@ -298,7 +298,7 @@ test_expect_success 'extension matching requires dot' '\n \ttest_cmp b.tar config-implicittar.foo\n '\n \n-test_expect_success NOT_MINGW 'only enabled filters are available remotely' '\n+test_expect_success 'only enabled filters are available remotely' '\n \ttest_must_fail git archive --remote=. --format=tar.foo HEAD \\\n \t\t>remote.tar.foo &&\n \tgit archive --remote=. --format=bar >remote.bar HEAD &&\n@@ -341,12 +341,12 @@ test_expect_success GZIP,GUNZIP 'extract tgz file' '\n \ttest_cmp b.tar j.tar\n '\n \n-test_expect_success GZIP,NOT_MINGW 'remote tar.gz is allowed by default' '\n+test_expect_success GZIP 'remote tar.gz is allowed by default' '\n \tgit archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&\n \ttest_cmp j.tgz remote.tar.gz\n '\n \n-test_expect_success GZIP,NOT_MINGW 'remote tar.gz can be disabled' '\n+test_expect_success GZIP 'remote tar.gz can be disabled' '\n \tgit config tar.tar.gz.remote false &&\n \ttest_must_fail git archive --remote=. --format=tar.gz HEAD \\\n \t\t>remote.tar.gz\n-- \n1.7.7.msysgit.1.1.g7b316\n"},{"id":"178249","messageId":"20111024223947.GA10481@sigill.intra.peff.net","threadId":"28759","inReplyTo":"1319472131-3968-4-git-send-email-kusmabite@gmail.com","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-24T22:39:47Z","receivedAt":"2011-10-24T22:39:47Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Oct 24, 2011 at 06:02:11PM +0200, Erik Faye-Lund wrote:\n\n> The POSIX-function fork is not supported on Windows. Use our\n> start_command API instead.\n> \n> As this is the last call-site that depends on the fork-stub in\n> compat/mingw.h, remove that as well.\n> \n> Add an undocumented flag to git-archive that tells it that the\n> action originated from a remote, so features can be disabled.\n> Thanks to Jeff King for work on this part.\n> \n> Remove the NOT_MINGW-prereq for t5000, as git-archive --remote\n> now works.\n> \n> Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>\n> Helped-by: Jeff King <peff@peff.net>\n> ---\n\nAs with other versions of this series, I have no comment on the mingw\nbits. The archive.c parts still look sane to me. :)\n\n-Peff\n"},{"id":"179495","messageId":"201111151122.48378.trast@student.ethz.ch","threadId":"28759","inReplyTo":"1319472131-3968-4-git-send-email-kusmabite@gmail.com","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2011-11-15T10:22:48Z","receivedAt":"2011-11-15T10:22:48Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Erik Faye-Lund wrote:\n> The POSIX-function fork is not supported on Windows. Use our\n> start_command API instead.\n> \n> As this is the last call-site that depends on the fork-stub in\n> compat/mingw.h, remove that as well.\n> \n> Add an undocumented flag to git-archive that tells it that the\n> action originated from a remote, so features can be disabled.\n> Thanks to Jeff King for work on this part.\n> \n> Remove the NOT_MINGW-prereq for t5000, as git-archive --remote\n> now works.\n\nI see valgrind failures bisecting to this commit, like so:\n\n==19125== Syscall param execve(argv[i]) points to unaddressable byte(s)\n==19125==    at 0x5303CB7: execve (in /lib64/libc-2.11.3.so)\n==19125==    by 0x53045A5: execvpe (in /lib64/libc-2.11.3.so)\n==19125==    by 0x4B183C: execv_git_cmd (exec_cmd.c:137)\n==19125==    by 0x4F305E: start_command (run-command.c:277)\n==19125==    by 0x47F5C9: cmd_upload_archive (upload-archive.c:98)\n==19125==    by 0x4051F4: run_builtin (git.c:308)\n==19125==    by 0x40538F: handle_internal_command (git.c:466)\n==19125==    by 0x405556: main (git.c:553)\n==19125==  Address 0x7feffe7d0 is not stack'd, malloc'd or (recently) free'd\n\nwhen running 'make valgrind' in current master.  Let me know if you\nneed more information.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"179496","messageId":"20111115102807.GA18649@sigill.intra.peff.net","threadId":"28759","inReplyTo":"201111151122.48378.trast@student.ethz.ch","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-15T10:28:08Z","receivedAt":"2011-11-15T10:28:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Nov 15, 2011 at 11:22:48AM +0100, Thomas Rast wrote:\n\n> > Remove the NOT_MINGW-prereq for t5000, as git-archive --remote\n> > now works.\n> \n> I see valgrind failures bisecting to this commit, like so:\n> \n> ==19125== Syscall param execve(argv[i]) points to unaddressable byte(s)\n> ==19125==    at 0x5303CB7: execve (in /lib64/libc-2.11.3.so)\n> ==19125==    by 0x53045A5: execvpe (in /lib64/libc-2.11.3.so)\n> ==19125==    by 0x4B183C: execv_git_cmd (exec_cmd.c:137)\n> ==19125==    by 0x4F305E: start_command (run-command.c:277)\n> ==19125==    by 0x47F5C9: cmd_upload_archive (upload-archive.c:98)\n> ==19125==    by 0x4051F4: run_builtin (git.c:308)\n> ==19125==    by 0x40538F: handle_internal_command (git.c:466)\n> ==19125==    by 0x405556: main (git.c:553)\n> ==19125==  Address 0x7feffe7d0 is not stack'd, malloc'd or (recently) free'd\n> \n> when running 'make valgrind' in current master.  Let me know if you\n> need more information.\n\nWith which test, and on what OS? I couldn't replicate running\nt5000 on Linux.\n\n-Peff\n"},{"id":"179498","messageId":"201111151311.46832.trast@student.ethz.ch","threadId":"28759","inReplyTo":"20111115102807.GA18649@sigill.intra.peff.net","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2011-11-15T12:11:46Z","receivedAt":"2011-11-15T12:11:46Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Jeff King wrote:\n> On Tue, Nov 15, 2011 at 11:22:48AM +0100, Thomas Rast wrote:\n> > \n> > I see valgrind failures bisecting to this commit, like so:\n> > \n> > ==19125== Syscall param execve(argv[i]) points to unaddressable byte(s)\n> > ==19125==    at 0x5303CB7: execve (in /lib64/libc-2.11.3.so)\n> > ==19125==    by 0x53045A5: execvpe (in /lib64/libc-2.11.3.so)\n> > ==19125==    by 0x4B183C: execv_git_cmd (exec_cmd.c:137)\n> > ==19125==    by 0x4F305E: start_command (run-command.c:277)\n> > ==19125==    by 0x47F5C9: cmd_upload_archive (upload-archive.c:98)\n> > ==19125==    by 0x4051F4: run_builtin (git.c:308)\n> > ==19125==    by 0x40538F: handle_internal_command (git.c:466)\n> > ==19125==    by 0x405556: main (git.c:553)\n> > ==19125==  Address 0x7feffe7d0 is not stack'd, malloc'd or (recently) free'd\n> > \n> > when running 'make valgrind' in current master.  Let me know if you\n> > need more information.\n> \n> With which test, and on what OS? I couldn't replicate running\n> t5000 on Linux.\n\n11, and many others after it, on a pretty vanilla opensuse 11.4 VM I\nuse almost exclusively for the valgrind runs.  I used a pre-3.7 SVN\nvalgrind build, but 3.6.1 (shipped with opensuse) finds the same.\n\nBut after a closer look I think this patch just prodded it enough to\nunearth long-existing undefined behaviour: prepare_argv() summarizes\nto something like\n\nstatic void prepare_argv(const char **sent_argv, const char **argv)\n{\n\tchar *p, buf[4096];\n\n\tfor (p = buf;;) {\n\t\tlen = packet_read_line(0, p, (buf + sizeof buf) - p);\n\t\t/* ... p always points into buf ... */\n\t\tsent_argv[sent_argc++] = p;\n\t\tp += len;\n\t\t*p++ = 0;\n\t}\n\tsent_argv[sent_argc] = NULL;\n}\n\nThe code appears to have looked like this ever since the addition of\nthat file back in 39345a2 (Add git-upload-archive, 2006-09-07).  So\nthe elements of sent_argv have apparently always pointed into the\nstack-allocated 'buf'.\n\n(This correlates with the \"Address 0x7feffe7d0 is not stack'd\", even\nthough it's pretty clearly an address into the stack.)\n\nA quick band-aid would be to heap-allocate it instead:\n\ndiff --git i/builtin/upload-archive.c w/builtin/upload-archive.c\nindex c57e8bd..6ab50d3 100644\n--- i/builtin/upload-archive.c\n+++ w/builtin/upload-archive.c\n@@ -22,9 +22,10 @@ static const char lostchild[] =\n static void prepare_argv(const char **sent_argv, const char **argv)\n {\n \tconst char *arg_cmd = \"argument \";\n-\tchar *p, buf[4096];\n+\tchar *p, *buf;\n \tint sent_argc;\n \tint len;\n+\tbuf = xmalloc(4096);\n \n \t/* put received options in sent_argv[] */\n \tsent_argc = 2;\n@@ -32,7 +33,7 @@ static void prepare_argv(const char **sent_argv, const char **argv)\n \tsent_argv[1] = \"--remote-request\";\n \tfor (p = buf;;) {\n \t\t/* This will die if not enough free space in buf */\n-\t\tlen = packet_read_line(0, p, (buf + sizeof buf) - p);\n+\t\tlen = packet_read_line(0, p, (buf + 4096) - p);\n \t\tif (len == 0)\n \t\t\tbreak;\t/* got a flush */\n \t\tif (sent_argc > MAX_ARGS - 2)\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"179516","messageId":"20111115173715.GA4478@sigill.intra.peff.net","threadId":"28759","inReplyTo":"201111151311.46832.trast@student.ethz.ch","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-15T17:37:15Z","receivedAt":"2011-11-15T17:37:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Nov 15, 2011 at 01:11:46PM +0100, Thomas Rast wrote:\n\n> But after a closer look I think this patch just prodded it enough to\n> unearth long-existing undefined behaviour: prepare_argv() summarizes\n> to something like\n> \n> static void prepare_argv(const char **sent_argv, const char **argv)\n> {\n> \tchar *p, buf[4096];\n> \n> \tfor (p = buf;;) {\n> \t\tlen = packet_read_line(0, p, (buf + sizeof buf) - p);\n> \t\t/* ... p always points into buf ... */\n> \t\tsent_argv[sent_argc++] = p;\n> \t\tp += len;\n> \t\t*p++ = 0;\n> \t}\n> \tsent_argv[sent_argc] = NULL;\n> }\n> \n> The code appears to have looked like this ever since the addition of\n> that file back in 39345a2 (Add git-upload-archive, 2006-09-07).  So\n> the elements of sent_argv have apparently always pointed into the\n> stack-allocated 'buf'.\n\nOh, yikes. That is definitely the problem, but it does come from\nc09cd77e. The prepare_argv function used to be \"run_upload_archive\", and\nit would prepare argv on the stack, call into write_archive with it, and\nthen return; nobody else cares about the value afterwards.\n\nErik's patch converts it into a function that writes the new argv into a\nparameter and returns, and the now-invalid stack-allocated memory is\nused by the calling function.\n\n> A quick band-aid would be to heap-allocate it instead:\n\nThat works.  An even shorter band-aid is to mark it as \"static\".\n\nI think the code would be more readable if it just used the new\nargv_array.\n\nJunio, this bug is in 1.7.8-rc*. Do you want the one-liner fix for the\nrelease, or the nicer fix?\n\n-Peff\n"},{"id":"179518","messageId":"CABPQNSbu9bb5UG1ihi2vGX5ZkpvjfjaXrT8bhDGZHb=n9RbjSg@mail.gmail.com","threadId":"28759","inReplyTo":"20111115173715.GA4478@sigill.intra.peff.net","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-11-15T17:44:38Z","receivedAt":"2011-11-15T17:44:38Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Tue, Nov 15, 2011 at 6:37 PM, Jeff King <peff@peff.net> wrote:\n> On Tue, Nov 15, 2011 at 01:11:46PM +0100, Thomas Rast wrote:\n>\n>> But after a closer look I think this patch just prodded it enough to\n>> unearth long-existing undefined behaviour: prepare_argv() summarizes\n>> to something like\n>>\n>> static void prepare_argv(const char **sent_argv, const char **argv)\n>> {\n>>       char *p, buf[4096];\n>>\n>>       for (p = buf;;) {\n>>               len = packet_read_line(0, p, (buf + sizeof buf) - p);\n>>               /* ... p always points into buf ... */\n>>               sent_argv[sent_argc++] = p;\n>>               p += len;\n>>               *p++ = 0;\n>>       }\n>>       sent_argv[sent_argc] = NULL;\n>> }\n>>\n>> The code appears to have looked like this ever since the addition of\n>> that file back in 39345a2 (Add git-upload-archive, 2006-09-07).  So\n>> the elements of sent_argv have apparently always pointed into the\n>> stack-allocated 'buf'.\n>\n> Oh, yikes. That is definitely the problem, but it does come from\n> c09cd77e. The prepare_argv function used to be \"run_upload_archive\", and\n> it would prepare argv on the stack, call into write_archive with it, and\n> then return; nobody else cares about the value afterwards.\n>\n> Erik's patch converts it into a function that writes the new argv into a\n> parameter and returns, and the now-invalid stack-allocated memory is\n> used by the calling function.\n>\n\nOutch. Thanks for spotting.\n\n>> A quick band-aid would be to heap-allocate it instead:\n>\n> That works.  An even shorter band-aid is to mark it as \"static\".\n\nHmm, I seem to remember spotting it myself at some point and fixing it\nby marking it as static. I guess I must have forgot to push it...\n\n> I think the code would be more readable if it just used the new\n> argv_array.\n>\n\nOooh, nice. The whole argv_array slipped past me, I like it!\n"},{"id":"179521","messageId":"20111115181840.GA15290@sigill.intra.peff.net","threadId":"28759","inReplyTo":"CABPQNSbu9bb5UG1ihi2vGX5ZkpvjfjaXrT8bhDGZHb=n9RbjSg@mail.gmail.com","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-15T18:18:40Z","receivedAt":"2011-11-15T18:18:40Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Nov 15, 2011 at 06:44:38PM +0100, Erik Faye-Lund wrote:\n\n> > I think the code would be more readable if it just used the new\n> > argv_array.\n> >\n> Oooh, nice. The whole argv_array slipped past me, I like it!\n\nI don't think it existed when you started on this series. :)\n\n-Peff\n"},{"id":"179522","messageId":"m2hb25cj5e.fsf@igel.home","threadId":"28759","inReplyTo":"201111151311.46832.trast@student.ethz.ch","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Andreas Schwab","fromEmail":"schwab@linux-m68k.org","sentAt":"2011-11-15T18:53:01Z","receivedAt":"2011-11-15T18:53:01Z","isPatch":true,"sender":{"key":"schwab@linux-m68k.org","avatar":"https://avatars.githubusercontent.com/u/2175493?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> But after a closer look I think this patch just prodded it enough to\n> unearth long-existing undefined behaviour: prepare_argv() summarizes\n> to something like\n>\n> static void prepare_argv(const char **sent_argv, const char **argv)\n> {\n> \tchar *p, buf[4096];\n>\n> \tfor (p = buf;;) {\n> \t\tlen = packet_read_line(0, p, (buf + sizeof buf) - p);\n> \t\t/* ... p always points into buf ... */\n> \t\tsent_argv[sent_argc++] = p;\n> \t\tp += len;\n> \t\t*p++ = 0;\n> \t}\n> \tsent_argv[sent_argc] = NULL;\n> }\n>\n> The code appears to have looked like this ever since the addition of\n> that file back in 39345a2 (Add git-upload-archive, 2006-09-07).  So\n> the elements of sent_argv have apparently always pointed into the\n> stack-allocated 'buf'.\n>\n> (This correlates with the \"Address 0x7feffe7d0 is not stack'd\", even\n> though it's pretty clearly an address into the stack.)\n>\n> A quick band-aid would be to heap-allocate it instead:\n\nOr allocate it in the caller:\n\ndiff --git a/builtin/upload-archive.c b/builtin/upload-archive.c\nindex c57e8bd..f0f843e 100644\n--- a/builtin/upload-archive.c\n+++ b/builtin/upload-archive.c\n@@ -18,11 +18,12 @@ static const char lostchild[] =\n \"git upload-archive: archiver process was lost\";\n \n #define MAX_ARGS (64)\n+#define ARGV_BUF_SIZE 4096\n \n-static void prepare_argv(const char **sent_argv, const char **argv)\n+static void prepare_argv(const char **sent_argv, char *buf, const char **argv)\n {\n \tconst char *arg_cmd = \"argument \";\n-\tchar *p, buf[4096];\n+\tchar *p;\n \tint sent_argc;\n \tint len;\n \n@@ -32,7 +33,7 @@ static void prepare_argv(const char **sent_argv, const char **argv)\n \tsent_argv[1] = \"--remote-request\";\n \tfor (p = buf;;) {\n \t\t/* This will die if not enough free space in buf */\n-\t\tlen = packet_read_line(0, p, (buf + sizeof buf) - p);\n+\t\tlen = packet_read_line(0, p, (buf + ARGV_BUF_SIZE) - p);\n \t\tif (len == 0)\n \t\t\tbreak;\t/* got a flush */\n \t\tif (sent_argc > MAX_ARGS - 2)\n@@ -85,6 +86,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)\n {\n \tconst char *sent_argv[MAX_ARGS];\n \tstruct child_process cld = { sent_argv };\n+\tchar argv_buf[ARGV_BUF_SIZE];\n \tcld.out = cld.err = -1;\n \tcld.git_cmd = 1;\n \n@@ -94,7 +96,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)\n \tif (!enter_repo(argv[1], 0))\n \t\tdie(\"'%s' does not appear to be a git repository\", argv[1]);\n \n-\tprepare_argv(sent_argv, argv);\n+\tprepare_argv(sent_argv, argv_buf, argv);\n \tif (start_command(&cld)) {\n \t\tint err = errno;\n \t\tpacket_write(1, \"NACK fork failed on the remote side\\n\");\n-- \n1.7.7.3\n\n\nAndreas.\n\n-- \nAndreas Schwab, schwab@linux-m68k.org\nGPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5\n\"And now for something completely different.\"\n"},{"id":"179523","messageId":"7vobwdus7w.fsf@alter.siamese.dyndns.org","threadId":"28759","inReplyTo":"20111115173715.GA4478@sigill.intra.peff.net","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-11-15T18:59:47Z","receivedAt":"2011-11-15T18:59:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Junio, this bug is in 1.7.8-rc*. Do you want the one-liner fix for the\n> release, or the nicer fix?\n\nLet's just do \"static\" for now, if we know the array is large enough.\n"},{"id":"179525","messageId":"20111115191832.GA16030@sigill.intra.peff.net","threadId":"28759","inReplyTo":"7vobwdus7w.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v4 3/3] upload-archive: use start_command instead of fork","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-15T19:18:32Z","receivedAt":"2011-11-15T19:18:32Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Nov 15, 2011 at 10:59:47AM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > Junio, this bug is in 1.7.8-rc*. Do you want the one-liner fix for the\n> > release, or the nicer fix?\n> \n> Let's just do \"static\" for now, if we know the array is large enough.\n\nOK, here it is.\n\nI think it's correct, but I couldn't reproduce the valgrind failure\nhere. Thomas, can you double check that this also solves your problem?\n\n-Peff\n\n-- >8 --\nSubject: [PATCH] upload-archive: don't return pointers to stack buffer\n\nThe prepare_argv function uses an internal stack-allocated\nbuffer to create the argv array that will be used to run\ngit-archive. Prior to c09cd77e, this was OK, as the\nfunction passed the argv array to write_archive itself, and\nthe stack buffer was valid during its use.\n\nSince c09cd77e, however, the function returns an argv array\nwith pointers pointing into the stack buffer. The calling\nfunction then passes the result to start_command, which\ntries to execve using pointers to a now-invalid buffer.\n\nFix it by making the buffer static, which is a quick and\nsimple fix, and works because we only run this function once\nper process.\n\nCredit for finding the bug and most of the analysis goes to\nThomas Rast.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/upload-archive.c |    3 ++-\n 1 files changed, 2 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/upload-archive.c b/builtin/upload-archive.c\nindex c57e8bd..f47c0f0 100644\n--- a/builtin/upload-archive.c\n+++ b/builtin/upload-archive.c\n@@ -22,7 +22,8 @@\n static void prepare_argv(const char **sent_argv, const char **argv)\n {\n \tconst char *arg_cmd = \"argument \";\n-\tchar *p, buf[4096];\n+\tchar *p;\n+\tstatic char buf[4096];\n \tint sent_argc;\n \tint len;\n \n-- \n1.7.7.3.8.g38efa\n"},{"id":"179527","messageId":"20111115194603.GA19305@sigill.intra.peff.net","threadId":"28759","inReplyTo":"20111115191832.GA16030@sigill.intra.peff.net","subject":"[PATCH 1/2] upload-archive: drop extra argument to prepare_argv","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-15T19:46:03Z","receivedAt":"2011-11-15T19:46:03Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We pass a \"sent_argv\" which is an out-parameter to hold the\nargv that we were sent over the wire. But we also pass in\nthe \"argv\" we got on the command line, which is not used at\nall. Drop this useless and confusing parameter.\n\nThe parameter was obsoleted by c09cd77e, which moved the\nenter_repo function (which looked at argv[1]) out of\nprepare_argv and into cmd_upload_archive.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nOn Tue, Nov 15, 2011 at 02:18:32PM -0500, Jeff King wrote:\n\n> > Let's just do \"static\" for now, if we know the array is large enough.\n> \n> OK, here it is.\n\nAnd here's the other more invasive cleanup on top (patch 2 is the meaty\none).\n\n builtin/upload-archive.c |    4 ++--\n 1 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/upload-archive.c b/builtin/upload-archive.c\nindex f47c0f0..80575b9 100644\n--- a/builtin/upload-archive.c\n+++ b/builtin/upload-archive.c\n@@ -19,7 +19,7 @@\n \n #define MAX_ARGS (64)\n \n-static void prepare_argv(const char **sent_argv, const char **argv)\n+static void prepare_argv(const char **sent_argv)\n {\n \tconst char *arg_cmd = \"argument \";\n \tchar *p;\n@@ -95,7 +95,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)\n \tif (!enter_repo(argv[1], 0))\n \t\tdie(\"'%s' does not appear to be a git repository\", argv[1]);\n \n-\tprepare_argv(sent_argv, argv);\n+\tprepare_argv(sent_argv);\n \tif (start_command(&cld)) {\n \t\tint err = errno;\n \t\tpacket_write(1, \"NACK fork failed on the remote side\\n\");\n-- \n1.7.7.3.8.g38efa\n"},{"id":"179528","messageId":"20111115194958.GB19305@sigill.intra.peff.net","threadId":"28759","inReplyTo":"20111115191832.GA16030@sigill.intra.peff.net","subject":"[PATCH] upload-archive: use argv_array for sent parameters","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-15T19:49:58Z","receivedAt":"2011-11-15T19:49:58Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The existing prepare_argv uses a fixed-size static buffer to\nhold all of the arguments, and then puts pointers into the\nbuffer into a fixed-size array. Using argv_array gets rid of\nall of the manual bookkeeping and makes the code more\nreadable.\n\nIt also lifts the static limits on the size of the array.\nThis is convenient, but is perhaps a security regression, as\na malicious client can now ask us to create arbitrary-length\nargv arrays in memory.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nI think the code is way more readable and obvious.  Do we care about the\npotential DoS?  If so, we can still cap the number of arguments we'll\naccept. In practice, we never send more than a few.\n\n builtin/upload-archive.c |   45 +++++++++++++++++----------------------------\n 1 files changed, 17 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin/upload-archive.c b/builtin/upload-archive.c\nindex 80575b9..3830310 100644\n--- a/builtin/upload-archive.c\n+++ b/builtin/upload-archive.c\n@@ -7,6 +7,7 @@\n #include \"pkt-line.h\"\n #include \"sideband.h\"\n #include \"run-command.h\"\n+#include \"argv-array.h\"\n \n static const char upload_archive_usage[] =\n \t\"git upload-archive <repo>\";\n@@ -17,42 +18,28 @@\n static const char lostchild[] =\n \"git upload-archive: archiver process was lost\";\n \n-#define MAX_ARGS (64)\n-\n-static void prepare_argv(const char **sent_argv)\n+static void prepare_argv(struct argv_array *out)\n {\n \tconst char *arg_cmd = \"argument \";\n-\tchar *p;\n-\tstatic char buf[4096];\n-\tint sent_argc;\n-\tint len;\n \n-\t/* put received options in sent_argv[] */\n-\tsent_argc = 2;\n-\tsent_argv[0] = \"archive\";\n-\tsent_argv[1] = \"--remote-request\";\n-\tfor (p = buf;;) {\n+\targv_array_push(out, \"archive\");\n+\targv_array_push(out, \"--remote-request\");\n+\twhile (1) {\n+\t\tchar buf[4096];\n+\t\tint len;\n \t\t/* This will die if not enough free space in buf */\n-\t\tlen = packet_read_line(0, p, (buf + sizeof buf) - p);\n+\t\tlen = packet_read_line(0, buf, sizeof(buf));\n \t\tif (len == 0)\n \t\t\tbreak;\t/* got a flush */\n-\t\tif (sent_argc > MAX_ARGS - 2)\n-\t\t\tdie(\"Too many options (>%d)\", MAX_ARGS - 2);\n \n-\t\tif (p[len-1] == '\\n') {\n-\t\t\tp[--len] = 0;\n-\t\t}\n+\t\tif (buf[len-1] == '\\n')\n+\t\t\tbuf[--len] = 0;\n \t\tif (len < strlen(arg_cmd) ||\n-\t\t    strncmp(arg_cmd, p, strlen(arg_cmd)))\n+\t\t    strncmp(arg_cmd, buf, strlen(arg_cmd)))\n \t\t\tdie(\"'argument' token or flush expected\");\n \n-\t\tlen -= strlen(arg_cmd);\n-\t\tmemmove(p, p + strlen(arg_cmd), len);\n-\t\tsent_argv[sent_argc++] = p;\n-\t\tp += len;\n-\t\t*p++ = 0;\n+\t\targv_array_push(out, buf + strlen(arg_cmd));\n \t}\n-\tsent_argv[sent_argc] = NULL;\n }\n \n __attribute__((format (printf, 1, 2)))\n@@ -84,8 +71,8 @@ static ssize_t process_input(int child_fd, int band)\n \n int cmd_upload_archive(int argc, const char **argv, const char *prefix)\n {\n-\tconst char *sent_argv[MAX_ARGS];\n-\tstruct child_process cld = { sent_argv };\n+\tstruct argv_array sent_argv = ARGV_ARRAY_INIT;\n+\tstruct child_process cld = {0};\n \tcld.out = cld.err = -1;\n \tcld.git_cmd = 1;\n \n@@ -95,7 +82,8 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)\n \tif (!enter_repo(argv[1], 0))\n \t\tdie(\"'%s' does not appear to be a git repository\", argv[1]);\n \n-\tprepare_argv(sent_argv);\n+\tprepare_argv(&sent_argv);\n+\tcld.argv = sent_argv.argv;\n \tif (start_command(&cld)) {\n \t\tint err = errno;\n \t\tpacket_write(1, \"NACK fork failed on the remote side\\n\");\n@@ -138,5 +126,6 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)\n \t\tpacket_flush(1);\n \t\tbreak;\n \t}\n+\targv_array_clear(&sent_argv);\n \treturn 0;\n }\n-- \n1.7.7.3.8.g38efa\n"},{"id":"179531","messageId":"20111115213040.GA20451@sigill.intra.peff.net","threadId":"28759","inReplyTo":"20111115194958.GB19305@sigill.intra.peff.net","subject":"Re: [PATCH] upload-archive: use argv_array for sent parameters","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-15T21:30:40Z","receivedAt":"2011-11-15T21:30:40Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Nov 15, 2011 at 02:49:58PM -0500, Jeff King wrote:\n\n> The existing prepare_argv uses a fixed-size static buffer to\n> hold all of the arguments, and then puts pointers into the\n> buffer into a fixed-size array. Using argv_array gets rid of\n> all of the manual bookkeeping and makes the code more\n> readable.\n> \n> It also lifts the static limits on the size of the array.\n> This is convenient, but is perhaps a security regression, as\n> a malicious client can now ask us to create arbitrary-length\n> argv arrays in memory.\n> \n> Signed-off-by: Jeff King <peff@peff.net>\n\nSorry, I failed to mark the subject properly. If it was not obvious,\nthis is patch 2/2 of the cleanup.\n\n-Peff\n"}]}