OSDN Git Service

* dtable.cc (POSIX_NAMED_PIPE): New define.
authorcgf <cgf>
Sun, 16 Dec 2007 21:21:19 +0000 (21:21 +0000)
committercgf <cgf>
Sun, 16 Dec 2007 21:21:19 +0000 (21:21 +0000)
(POSIX_NAMED_PIPE_LEN): Ditto.
(dtable::add_archetype): Use crealloc_abort.
(dtable::init_std_file_from_handle): Specifically detect pipe stdin/stdout.
Pass name to build_fh_dev so that proper name is recorded.  Use binmode of fh
if it is set before using get_default_mode.  Set proper read/write access when
calling init().
(handle_to_fn): Handle pipes.
* fhandler.cc (fhandler_base::wait_overlapped): Add some debugging.
* fhandler.h (fhandler_base::set_name): Default to just setting the path_conv
name.
(fhandler_pipe::init): Declare.
* pipe.cc (struct pipesync): New struct.
(getov_result): New function.  Blocks and retrieves the result of an overlay
I/O operation.
(pipe_handler): New function.
(pipesync::pipesync): New function.  Initializer for pipesync struct.
(handler_pipe::init): Define.  Detects attempts to set up a "native" pipe
fhandler and creates a thread which accepts input from or output to the
non-cygwin pipe, creating a cygwin pipe wrapper around the non-cygwin pipe.
(fhandler_pipe::create): Add pipe-specific flags to call to init().
* exceptions.cc (ctrl_c_handler): Lock process while we determine what to do.

winsup/cygwin/ChangeLog
winsup/cygwin/dtable.cc
winsup/cygwin/exceptions.cc
winsup/cygwin/fhandler.cc
winsup/cygwin/fhandler.h
winsup/cygwin/pipe.cc

index eb54da9..4ea56f4 100644 (file)
@@ -1,3 +1,31 @@
+2007-12-16  Christopher Faylor  <me+cygwin@cgf.cx>
+
+       * dtable.cc (POSIX_NAMED_PIPE): New define.
+       (POSIX_NAMED_PIPE_LEN): Ditto.
+       (dtable::add_archetype): Use crealloc_abort.
+       (dtable::init_std_file_from_handle): Specifically detect pipe
+       stdin/stdout.  Pass name to build_fh_dev so that proper name is
+       recorded.  Use binmode of fh if it is set before using
+       get_default_mode.  Set proper read/write access when calling init().
+       (handle_to_fn): Handle pipes.
+       * fhandler.cc (fhandler_base::wait_overlapped): Add some debugging.
+       * fhandler.h (fhandler_base::set_name): Default to just setting the
+       path_conv name.
+       (fhandler_pipe::init): Declare.
+       * pipe.cc (struct pipesync): New struct.
+       (getov_result): New function.  Blocks and retrieves the result of an
+       overlay I/O operation.
+       (pipe_handler): New function.
+       (pipesync::pipesync): New function.  Initializer for pipesync struct.
+       (handler_pipe::init): Define.  Detects attempts to set up a "native"
+       pipe fhandler and creates a thread which accepts input from or output
+       to the non-cygwin pipe, creating a cygwin pipe wrapper around the
+       non-cygwin pipe.
+       (fhandler_pipe::create): Add pipe-specific flags to call to init().
+
+       * exceptions.cc (ctrl_c_handler): Lock process while we determine what
+       to do.
+
 2007-12-14  Corinna Vinschen  <corinna@vinschen.de>
 
        * include/cygwin/socket.h: Include sys/uio.h instead of cygwin/uio.h.
index 5753846..6fcf708 100644 (file)
@@ -41,6 +41,17 @@ static const NO_COPY DWORD std_consts[] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
 
 static const char *handle_to_fn (HANDLE, char *);
 
+#define DEVICE_PREFIX "\\device\\"
+#define DEVICE_PREFIX_LEN sizeof (DEVICE_PREFIX) - 1
+#define REMOTE "\\Device\\LanmanRedirector\\"
+#define REMOTE_LEN sizeof (REMOTE) - 1
+#define REMOTE1 "\\Device\\WinDfs\\Root\\"
+#define REMOTE1_LEN sizeof (REMOTE1) - 1
+#define NAMED_PIPE "\\Device\\NamedPipe\\"
+#define NAMED_PIPE_LEN sizeof (NAMED_PIPE) - 1
+#define POSIX_NAMED_PIPE "/Device/NamedPipe/"
+#define POSIX_NAMED_PIPE_LEN sizeof (POSIX_NAMED_PIPE) - 1
+
 /* Set aside space for the table of fds */
 void
 dtable_init ()
@@ -187,7 +198,7 @@ fhandler_base **
 dtable::add_archetype ()
 {
   if (farchetype++ >= narchetypes)
-    archetypes = (fhandler_base **) crealloc (archetypes, (narchetypes += initial_archetype_size) * sizeof archetypes[0]);
+    archetypes = (fhandler_base **) crealloc_abort (archetypes, (narchetypes += initial_archetype_size) * sizeof archetypes[0]);
   return archetypes + farchetype - 1;
 }
 
@@ -283,13 +294,6 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle)
          else
            dev = *console_dev;
        }
-      else if (ft == FILE_TYPE_PIPE)
-       {
-         if (fd == 0)
-           dev = *piper_dev;
-         else
-           dev = *pipew_dev;
-       }
       else if (wsock_started && getpeername ((SOCKET) handle, &sa, &sal) == 0)
        dev = *tcp_dev;
       else if (GetCommState (handle, &dcb))
@@ -297,7 +301,12 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle)
       else
        {
          name = handle_to_fn (handle, (char *) alloca (CYG_MAX_PATH + 100));
-         bin = 0;
+         if (!strncasematch (name, POSIX_NAMED_PIPE, POSIX_NAMED_PIPE_LEN))
+           /* nothing */;
+         else if (fd == 0)
+           dev = *piper_dev;
+         else
+           dev = *pipew_dev;
        }
     }
 
@@ -308,25 +317,31 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle)
       fhandler_base *fh;
 
       if (dev)
-       fh = build_fh_dev (dev);
+       fh = build_fh_dev (dev, name);
       else
        fh = build_fh_name (name);
 
       if (fh)
        cygheap->fdtab[fd] = fh;
 
-      if (!bin)
+      if (name)
        {
-         bin = fh->get_default_fmode (O_RDWR);
-         if (bin)
-           /* nothing */;
-         else if (dev)
-           bin = O_BINARY;
-         else if (name != unknown_file)
-           bin = fh->pc_binmode ();
+         bin = fh->pc_binmode ();
+         if (!bin)
+           {
+             bin = fh->get_default_fmode (O_RDWR);
+             if (!bin && dev)
+               bin = O_BINARY;
+           }
        }
 
-      fh->init (handle, GENERIC_READ | GENERIC_WRITE, bin);
+      DWORD access;
+      if (fd == 0)
+       access = GENERIC_READ;
+      else 
+       access = GENERIC_WRITE;  /* Should be rdwr for stderr but not sure that's
+                                   possible for some versions of handles */
+      fh->init (handle, access, bin);
       set_std_handle (fd);
       paranoid_printf ("fd %d, handle %p", fd, handle);
     }
@@ -824,11 +839,6 @@ dtable::vfork_child_fixup ()
 }
 #endif /*NEWVFORK*/
 
-#define DEVICE_PREFIX "\\device\\"
-#define DEVICE_PREFIX_LEN sizeof (DEVICE_PREFIX) - 1
-#define REMOTE "\\Device\\LanmanRedirector\\"
-#define REMOTE_LEN sizeof (REMOTE) - 1
-
 static const char *
 handle_to_fn (HANDLE h, char *posix_fn)
 {
@@ -900,6 +910,7 @@ handle_to_fn (HANDLE h, char *posix_fn)
     }
 
   char *w32 = win32_fn;
+  bool justslash = false;
   if (maxmatchlen)
     {
       n = strlen (maxmatchdos);
@@ -909,15 +920,38 @@ handle_to_fn (HANDLE h, char *posix_fn)
       memcpy (w32, maxmatchdos, n);
       w32[n] = '\\';
     }
+  else if (strncasematch (w32, NAMED_PIPE, NAMED_PIPE_LEN))
+    {
+      debug_printf ("pipe");
+      justslash = true;
+    }
   else if (strncasematch (w32, REMOTE, REMOTE_LEN))
     {
       w32 += REMOTE_LEN - 2;
       *w32 = '\\';
       debug_printf ("remote drive");
+      justslash = true;
+    }
+  else if (strncasematch (w32, REMOTE1, REMOTE1_LEN))
+    {
+      w32 += REMOTE1_LEN - 2;
+      *w32 = '\\';
+      debug_printf ("remote drive");
+      justslash = true;
     }
 
+  if (!justslash)
+    cygwin_conv_to_full_posix_path (w32, posix_fn);
+  else
+    {
+      char *s, *d;
+      for (s = w32, d = posix_fn; *s; s++, d++)
+       if (*s == '\\')
+         *d = '/';
+       else
+         *d = *s;
+    }
 
-  debug_printf ("derived path '%s'", w32);
-  cygwin_conv_to_full_posix_path (w32, posix_fn);
+  debug_printf ("derived path '%s', posix '%s'", w32, posix_fn);
   return posix_fn;
 }
index 06a9b54..fc361b5 100644 (file)
@@ -888,6 +888,7 @@ static BOOL WINAPI
 ctrl_c_handler (DWORD type)
 {
   static bool saw_close;
+  lock_process now;
 
   if (!cygwin_finished_initializing)
     {
index bc30a39..a479d1b 100644 (file)
@@ -1639,6 +1639,7 @@ fhandler_base::wait_overlapped (bool& res, bool writing, DWORD *bytes)
       switch (WaitForMultipleObjects (n, w4, false, INFINITE))
        {
        case WAIT_OBJECT_0:
+         debug_printf ("normal read");
          if (!bytes ||
              GetOverlappedResult (h, get_overlapped (), bytes, false))
            res = 1;
@@ -1649,12 +1650,14 @@ fhandler_base::wait_overlapped (bool& res, bool writing, DWORD *bytes)
            }
          break;
        case WAIT_OBJECT_0 + 1:
+         debug_printf ("got a signal");
          CancelIo (h);
          set_errno (EINTR);
          res = 0;
          break;
        default:
          err = GetLastError ();
+         debug_printf ("WFMO error, %E");
          goto err;
          break;
        }
index 665dd51..45588fe 100644 (file)
@@ -149,6 +149,7 @@ class fhandler_base
   path_conv pc;
 
   virtual void set_name (path_conv &pc);
+  virtual void set_name (const char *s) {pc.set_normalized_path (s, false);}
   int error () const {return pc.error;}
   void set_error (int error) {pc.error = error;}
   bool exists () const {return pc.exists ();}
@@ -546,6 +547,7 @@ public:
   int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3)));
   int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3)));
   int ready_for_read (int fd, DWORD howlong);
+  void init (HANDLE, DWORD, mode_t);
   static int create (fhandler_pipe *[2], unsigned, int);
   static int create_selectable (LPSECURITY_ATTRIBUTES, HANDLE&, HANDLE&, DWORD);
 };
index b9314aa..a6e4fff 100644 (file)
@@ -34,6 +34,157 @@ fhandler_pipe::fhandler_pipe ()
   need_fork_fixup (true);
 }
 
+struct pipesync
+{
+  bool reader;
+  HANDLE ev, non_cygwin_h, ret_handle;
+  pipesync(HANDLE, DWORD);
+  int operator == (int x) const {return !!ev;}
+  static DWORD WINAPI handler (LPVOID *);
+};
+
+inline bool
+getov_result (HANDLE h, DWORD& nbytes, LPOVERLAPPED ov)
+{
+  if (ov && (GetLastError () != ERROR_IO_PENDING
+            || !GetOverlappedResult (h, ov, &nbytes, true)))
+    {
+      __seterrno ();
+      return false;
+    }
+  return true;
+}
+
+static DWORD WINAPI
+pipe_handler (LPVOID in_ps)
+{
+  pipesync ps = *(pipesync *) in_ps;
+  HANDLE in, out;
+  DWORD err = fhandler_pipe::create_selectable (&sec_none_nih, in, out, 0);
+  if (err)
+    {
+      SetLastError (err);
+      system_printf ("couldn't create a shadow pipe for non-cygwin pipe I/O, %E");
+      return 0;
+    }
+  ((pipesync *) in_ps)->ret_handle = ps.reader ? in : out;
+  SetEvent (ps.ev);
+
+  char buf[4096];
+  DWORD read_bytes, write_bytes;
+  HANDLE hread, hwrite, hclose;
+  OVERLAPPED ov, *rov, *wov;
+  memset (&ov, 0, sizeof (ov));
+  ov.hEvent = CreateEvent (&sec_none_nih, true, false, NULL);
+  if (ps.reader)
+    {
+      hread = ps.non_cygwin_h;
+      hclose = hwrite = out;
+      wov = &ov;
+      rov = NULL;
+    }
+  else
+    {
+      hclose = hread = in;
+      hwrite = ps.non_cygwin_h;
+      rov = &ov;
+      wov = NULL;
+    }
+
+  while (1)
+    {
+      ResetEvent (ov.hEvent);
+      BOOL res = ReadFile (hread, buf, 4096, &read_bytes, rov);
+      if (!res && !getov_result (hread, read_bytes, rov))
+       break;
+      if (!read_bytes)
+       break;
+
+      res = WriteFile (hwrite, buf, read_bytes, &write_bytes, wov);
+      if (!res && !getov_result (hwrite, write_bytes, wov))
+       break;
+      if (write_bytes != read_bytes)
+       break;
+    }
+
+  err = GetLastError ();
+  CloseHandle (ov.hEvent);
+  CloseHandle (hclose);
+  CloseHandle (ps.non_cygwin_h);
+  SetLastError (err);
+  return 0;
+}
+      
+
+pipesync::pipesync (HANDLE f, DWORD is_reader):
+  reader (false), ret_handle (NULL)
+{
+  ev = CreateEvent (&sec_none_nih, true, false, NULL);
+  if (!ev)
+    {
+      system_printf ("couldn't create synchronization event for non-cygwin pipe, %E");
+      goto out;
+    }
+  non_cygwin_h = f;
+  reader = !!is_reader;
+  ret_handle = NULL;
+
+  DWORD tid;
+  HANDLE ht = CreateThread (&sec_none_nih, 0, pipe_handler, this, 0, &tid);
+
+  if (!ht)
+    goto out;
+  CloseHandle (ht);
+
+  switch (WaitForSingleObject (ev, INFINITE))
+    {
+    case WAIT_OBJECT_0:
+      break;
+    default:
+      system_printf ("WFSO failed waiting for synchronization event for non-cygwin pipe, %E");
+      break;
+    }
+
+out:
+  if (ev)
+    {
+      CloseHandle (ev);
+      ev = NULL;
+    }
+  return;
+}
+
+#define WINPIPE "\\\\.\\pipe\\"
+void
+fhandler_pipe::init (HANDLE f, DWORD a, mode_t bin)
+{
+  // FIXME: Have to clean this up someday
+  if (!*get_win32_name () && get_name ())
+    {
+      char *hold_normalized_name = (char *) alloca (strlen (get_name ()) + 1);
+      strcpy (hold_normalized_name, get_name ());
+      char *s, *d;
+      for (s = hold_normalized_name, d = (char *) get_win32_name (); *s; s++, d++)
+       if (*s == '/')
+         *d = '\\';
+       else
+         *d = *s;
+      *d = '\0';
+      set_name (hold_normalized_name);
+    }
+
+  bool opened_properly = a & FILE_CREATE_PIPE_INSTANCE;
+  a &= ~FILE_CREATE_PIPE_INSTANCE;
+  if (!opened_properly)
+    {
+      pipesync ps (f, a & GENERIC_READ);
+      f = ps.ret_handle;
+    }
+
+  fhandler_base::init (f, a, bin);
+  setup_overlapped ();
+}
+
 extern "C" int sscanf (const char *, const char *, ...);
 
 int
@@ -284,16 +435,14 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode)
       fhs[1] = (fhandler_pipe *) build_fh_dev (*pipew_dev);
 
       int binmode = mode & O_TEXT ?: O_BINARY;
-      fhs[0]->init (r, GENERIC_READ, binmode);
-      fhs[1]->init (w, GENERIC_WRITE, binmode);
+      fhs[0]->init (r, FILE_CREATE_PIPE_INSTANCE | GENERIC_READ, binmode);
+      fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, binmode);
       if (mode & O_NOINHERIT)
        {
         fhs[0]->close_on_exec (true);
         fhs[1]->close_on_exec (true);
        }
 
-      fhs[0]->setup_overlapped ();
-      fhs[1]->setup_overlapped ();
       res = 0;
     }