https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=a10d96923188977446ebd84323b47f7085fb5cb4

commit a10d96923188977446ebd84323b47f7085fb5cb4
Author: Corinna Vinschen <cori...@vinschen.de>
Date:   Mon Jan 11 12:35:41 2016 +0100

    Return unique inode numbers when calling stat/fstat on pipes and IP sockets
    
            * fhandler.h (class fhandler_base): Convert unique_id to int64_t.
            (fhandler_base::set_ino): New protected inline method.
            (fhandler_base::get_unique_id): Convert to int64_t.
            (fhandler_base::set_unique_id): New inline method taking int64_t.
            (fhandler_pipe::fstat): Declare.
            (fhandler_pipe::init): Take extra parameter.
            (fhandler_pipe::create): Ditto.
            * fhandler_socket.cc (fhandler_socket::init_events): Set inode 
number
            to serial number.
            (fhandler_socket::fstat): Set device to DEV_TCP_MAJOR.  Create 
st_ino
            from get_ino.
            * include/cygwin/signal.h (struct _sigcommune): Replace
            _si_pipe_fhandler with _si_pipe_unique_id.
            * pinfo.h (_pinfo::pipe_fhandler): Take unique id instead of HANDLE.
            * pinfo.cc (commune_process): Accommodate change to 
_si_pipe_unique_id.
            (_pinfo::commune_request): Ditto.
            (_pinfo::pipe_fhandler): Ditto.
            * pipe.cc (fhandler_pipe::init): Take unique id as argument and set
            inode number and unique_id from there.
            (fhandler_pipe::open): Rework to find any matching pipe from unique
            id in filename.
            (fhandler_pipe::get_proc_fd_name): Create filename using inode 
number.
            (fhandler_pipe::create): Generate and return unique id from process 
pid
            and pipe_unique_id.  In outer method, call init with additional 
unique
            id as parameter.
            (fhandler_pipe::fstat): New method.
            (pipe_worker): Accommodate using 64 bit inode number in filename.
    
    Signed-off-by: Corinna Vinschen <cori...@vinschen.de>

Diff:
---
 winsup/cygwin/fhandler.h              |  11 ++--
 winsup/cygwin/fhandler_socket.cc      |   5 +-
 winsup/cygwin/include/cygwin/signal.h |   2 +-
 winsup/cygwin/pinfo.cc                |  10 ++--
 winsup/cygwin/pinfo.h                 |   2 +-
 winsup/cygwin/pipe.cc                 | 100 +++++++++++++++++++++++-----------
 winsup/cygwin/release/2.4.0           |   3 +
 7 files changed, 88 insertions(+), 45 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index adb8441..8bcf83f 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -182,8 +182,9 @@ class fhandler_base
   size_t rabuflen;
 
   /* Used for advisory file locking.  See flock.cc.  */
-  long long unique_id;
+  int64_t unique_id;
   void del_my_locks (del_lock_called_from);
+  void set_ino (ino_t i) { ino = i; }
 
   HANDLE read_state;
 
@@ -304,7 +305,7 @@ class fhandler_base
   const char *get_win32_name () { return pc.get_win32 (); }
   virtual dev_t get_dev () { return get_device (); }
   ino_t get_ino () { return ino ?: ino = hash_path_name (0, 
pc.get_nt_native_path ()); }
-  long long get_unique_id () const { return unique_id; }
+  int64_t get_unique_id () const { return unique_id; }
   /* Returns name used for /proc/<pid>/fd in buf. */
   virtual char *get_proc_fd_name (char *buf);
 
@@ -319,6 +320,7 @@ class fhandler_base
   int open_null (int flags);
   virtual int open (int, mode_t);
   virtual void open_setup (int flags);
+  void set_unique_id (int64_t u) { unique_id = u; }
   void set_unique_id () { NtAllocateLocallyUniqueId ((PLUID) &unique_id); }
 
   int close_with_arch ();
@@ -731,13 +733,14 @@ public:
   int open (int flags, mode_t mode = 0);
   int dup (fhandler_base *child, int);
   int ioctl (unsigned int cmd, void *);
+  int __reg2 fstat (struct stat *buf);
   int __reg2 fstatvfs (struct statvfs *buf);
   int __reg3 fadvise (off_t, off_t, int);
   int __reg3 ftruncate (off_t, bool);
-  int init (HANDLE, DWORD, mode_t);
+  int init (HANDLE, DWORD, mode_t, int64_t);
   static int create (fhandler_pipe *[2], unsigned, int);
   static DWORD create (LPSECURITY_ATTRIBUTES, HANDLE *, HANDLE *, DWORD,
-                      const char *, DWORD);
+                      const char *, DWORD, int64_t *unique_id = NULL);
   fhandler_pipe (void *) {}
 
   void copyto (fhandler_base *x)
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index 21bc731..094cc65 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -594,6 +594,7 @@ fhandler_socket::init_events ()
        InterlockedIncrement (&socket_serial_number);
       if (!new_serial_number)  /* 0 is reserved for global mutex */
        InterlockedIncrement (&socket_serial_number);
+      set_ino (new_serial_number);
       RtlInitUnicodeString (&uname, sock_shared_name (name, 
new_serial_number));
       InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF,
                                  get_session_parent_dir (),
@@ -937,8 +938,8 @@ fhandler_socket::fstat (struct stat *buf)
       res = fhandler_base::fstat (buf);
       if (!res)
        {
-         buf->st_dev = 0;
-         buf->st_ino = (ino_t) ((uintptr_t) get_handle ());
+         buf->st_dev = FHDEV (DEV_TCP_MAJOR, 0);
+         buf->st_ino = (ino_t) get_ino ();
          buf->st_mode = S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO;
          buf->st_size = 0;
        }
diff --git a/winsup/cygwin/include/cygwin/signal.h 
b/winsup/cygwin/include/cygwin/signal.h
index 350a912..04ddb69 100644
--- a/winsup/cygwin/include/cygwin/signal.h
+++ b/winsup/cygwin/include/cygwin/signal.h
@@ -188,7 +188,7 @@ struct _sigcommune
   __extension__ union
   {
     int _si_fd;
-    void *_si_pipe_fhandler;
+    int64_t _si_pipe_unique_id;
     char *_si_str;
   };
 };
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index d0b4cd9..be32cfd 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -622,11 +622,11 @@ commune_process (void *arg)
     case PICOM_PIPE_FHANDLER:
       {
        sigproc_printf ("processing PICOM_FDS");
-       HANDLE hdl = si._si_commune._si_pipe_fhandler;
+       int64_t unique_id = si._si_commune._si_pipe_unique_id;
        unsigned int n = 0;
        cygheap_fdenum cfd;
        while (cfd.next () >= 0)
-         if (cfd->get_handle () == hdl)
+         if (cfd->get_unique_id () == unique_id)
            {
              fhandler_pipe *fh = cfd;
              n = sizeof *fh;
@@ -701,7 +701,7 @@ _pinfo::commune_request (__uint32_t code, ...)
   switch (code)
     {
     case PICOM_PIPE_FHANDLER:
-      si._si_commune._si_pipe_fhandler = va_arg (args, HANDLE);
+      si._si_commune._si_pipe_unique_id = va_arg (args, int64_t);
       break;
 
     case PICOM_FD:
@@ -781,13 +781,13 @@ out:
 }
 
 fhandler_pipe *
-_pinfo::pipe_fhandler (HANDLE hdl, size_t &n)
+_pinfo::pipe_fhandler (int64_t unique_id, size_t &n)
 {
   if (!this || !pid)
     return NULL;
   if (pid == myself->pid)
     return NULL;
-  commune_result cr = commune_request (PICOM_PIPE_FHANDLER, hdl);
+  commune_result cr = commune_request (PICOM_PIPE_FHANDLER, unique_id);
   n = cr.n;
   return (fhandler_pipe *) cr.s;
 }
diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h
index 1d6a72c..65a9e89 100644
--- a/winsup/cygwin/pinfo.h
+++ b/winsup/cygwin/pinfo.h
@@ -103,7 +103,7 @@ public:
 
   commune_result commune_request (__uint32_t, ...);
   bool alive ();
-  fhandler_pipe *pipe_fhandler (HANDLE, size_t &);
+  fhandler_pipe *pipe_fhandler (int64_t, size_t &);
   char *fd (int fd, size_t &);
   char *fds (size_t &);
   char *root (size_t &);
diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc
index 945c8fc..4ec4fa4 100644
--- a/winsup/cygwin/pipe.cc
+++ b/winsup/cygwin/pipe.cc
@@ -31,7 +31,7 @@ fhandler_pipe::fhandler_pipe ()
 }
 
 int
-fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode)
+fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode, int64_t uniq_id)
 {
   /* FIXME: Have to clean this up someday
      FIXME: Do we have to check for both !get_win32_name() and
@@ -54,6 +54,8 @@ fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode)
   a &= ~FILE_CREATE_PIPE_INSTANCE;
   fhandler_base::init (f, a, mode);
   close_on_exec (mode & O_CLOEXEC);
+  set_ino (uniq_id);
+  set_unique_id (uniq_id | !!(mode & GENERIC_WRITE));
   if (opened_properly)
     setup_overlapped ();
   else
@@ -66,27 +68,33 @@ extern "C" int sscanf (const char *, const char *, ...);
 int
 fhandler_pipe::open (int flags, mode_t mode)
 {
-  HANDLE proc, pipe_hdl, nio_hdl = NULL;
-  fhandler_pipe *fh = NULL;
+  HANDLE proc, nio_hdl = NULL;
+  int64_t uniq_id;
+  fhandler_pipe *fh = NULL, *fhr = NULL, *fhw = NULL;
   size_t size;
   int pid, rwflags = (flags & O_ACCMODE);
   bool inh;
+  bool got_one = false;
 
-  sscanf (get_name (), "/proc/%d/fd/pipe:[%lu]",
-                      &pid, (unsigned long *) &pipe_hdl);
+  sscanf (get_name (), "/proc/%d/fd/pipe:[%lld]",
+                      &pid, (long long *) &uniq_id);
   if (pid == myself->pid)
     {
       cygheap_fdenum cfd (true);
       while (cfd.next () >= 0)
        {
-         if (cfd->get_handle () != pipe_hdl)
+         /* Windows doesn't allow to copy a pipe HANDLE with another access
+            mode.  So we check for read and write side of pipe and try to
+            find the one matching the requested access mode. */
+         if (cfd->get_unique_id () == uniq_id)
+           got_one = true;
+         else if (cfd->get_unique_id () == uniq_id + 1)
+           got_one = true;
+         else
            continue;
          if ((rwflags == O_RDONLY && !(cfd->get_access () & GENERIC_READ))
              || (rwflags == O_WRONLY && !(cfd->get_access () & GENERIC_WRITE)))
-           {
-             set_errno (EACCES);
-             return 0;
-           }
+           continue;
          cfd->copyto (this);
          set_io_handle (NULL);
          pc.reset_conv_handle ();
@@ -94,7 +102,9 @@ fhandler_pipe::open (int flags, mode_t mode)
            return 1;
          return 0;
        }
-      set_errno (ENOENT);
+      /* Found the pipe but access mode didn't match? EACCES.
+        Otherwise ENOENT */
+      set_errno (got_one ? EACCES : ENOENT);
       return 0;
     }
 
@@ -109,27 +119,30 @@ fhandler_pipe::open (int flags, mode_t mode)
       __seterrno ();
       return 0;
     }
-  if (!(fh = p->pipe_fhandler (pipe_hdl, size)) || !size)
+  fhr = p->pipe_fhandler (uniq_id, size);
+  if (fhr && rwflags == O_RDONLY)
+    fh = fhr;
+  else
     {
-      set_errno (ENOENT);
-      goto out;
+      fhw = p->pipe_fhandler (uniq_id + 1, size);
+      if (fhw && rwflags == O_WRONLY)
+       fh = fhw;
     }
-  /* Too bad, but Windows only allows the same access mode when dup'ing
-     the pipe. */
-  if ((rwflags == O_RDONLY && !(fh->get_access () & GENERIC_READ))
-      || (rwflags == O_WRONLY && !(fh->get_access () & GENERIC_WRITE)))
+  if (!fh)
     {
-      set_errno (EACCES);
+      /* Too bad, but Windows only allows the same access mode when dup'ing
+        the pipe. */
+      set_errno (fhr || fhw ? EACCES : ENOENT);
       goto out;
     }
   inh = !(flags & O_CLOEXEC);
-  if (!DuplicateHandle (proc, pipe_hdl, GetCurrentProcess (), &nio_hdl,
-                       0, inh, DUPLICATE_SAME_ACCESS))
+  if (!DuplicateHandle (proc, fh->get_handle (), GetCurrentProcess (),
+                       &nio_hdl, 0, inh, DUPLICATE_SAME_ACCESS))
     {
       __seterrno ();
       goto out;
     }
-  init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY);
+  init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY, fh->get_ino ());
   cfree (fh);
   CloseHandle (proc);
   return 1;
@@ -168,7 +181,7 @@ fhandler_pipe::ftruncate (off_t length, bool allow_truncate)
 char *
 fhandler_pipe::get_proc_fd_name (char *buf)
 {
-  __small_sprintf (buf, "pipe:[%lu]", get_handle ());
+  __small_sprintf (buf, "pipe:[%D]", get_ino ());
   return buf;
 }
 
@@ -199,7 +212,8 @@ fhandler_pipe::dup (fhandler_base *child, int flags)
    unlike CreatePipe, which returns a bool for success or failure.  */
 DWORD
 fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w,
-                      DWORD psize, const char *name, DWORD open_mode)
+                      DWORD psize, const char *name, DWORD open_mode,
+                      int64_t *unique_id)
 {
   /* Default to error. */
   if (r)
@@ -241,8 +255,12 @@ fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, 
PHANDLE r, PHANDLE w,
     {
       static volatile ULONG pipe_unique_id;
       if (!name)
-       __small_sprintf (pipename + len, "pipe-%p",
-                        InterlockedIncrement ((LONG *) &pipe_unique_id));
+       {
+         LONG id = InterlockedIncrement ((LONG *) &pipe_unique_id);
+         __small_sprintf (pipename + len, "pipe-%p", id);
+         if (unique_id)
+           *unique_id = ((int64_t) id << 32 | GetCurrentProcessId ());
+       }
 
       debug_printf ("name %s, size %u, mode %s", pipename, psize,
                    (pipe_mode & PIPE_TYPE_MESSAGE)
@@ -341,8 +359,9 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned 
psize, int mode)
   HANDLE r, w;
   SECURITY_ATTRIBUTES *sa = sec_none_cloexec (mode);
   int res = -1;
+  int64_t unique_id;
 
-  int ret = create (sa, &r, &w, psize, NULL, FILE_FLAG_OVERLAPPED);
+  int ret = create (sa, &r, &w, psize, NULL, FILE_FLAG_OVERLAPPED, &unique_id);
   if (ret)
     __seterrno_from_win_error (ret);
   else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL)
@@ -358,8 +377,10 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned 
psize, int mode)
   else
     {
       mode |= mode & O_TEXT ?: O_BINARY;
-      fhs[0]->init (r, FILE_CREATE_PIPE_INSTANCE | GENERIC_READ, mode);
-      fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, mode);
+      fhs[0]->init (r, FILE_CREATE_PIPE_INSTANCE | GENERIC_READ, mode,
+                   unique_id);
+      fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, mode,
+                   unique_id);
       res = 0;
     }
 
@@ -395,6 +416,21 @@ fhandler_pipe::ioctl (unsigned int cmd, void *p)
 }
 
 int __reg2
+fhandler_pipe::fstat (struct stat *buf)
+{
+  int ret = fhandler_base::fstat (buf);
+  if (!ret)
+    {
+      buf->st_dev = FH_PIPE;
+      /* Don't use get_ino, it doesn't return 0 but a hash instead. */
+      if (!(buf->st_ino = get_unique_id ()))
+       sscanf (get_name (), "/proc/%*d/fd/pipe:[%lld]",
+                            (long long *) &buf->st_ino);
+    }
+  return ret;
+}
+
+int __reg2
 fhandler_pipe::fstatvfs (struct statvfs *sfs)
 {
   set_errno (EBADF);
@@ -410,10 +446,10 @@ pipe_worker (int filedes[2], unsigned int psize, int mode)
     {
       cygheap_fdnew fdin;
       cygheap_fdnew fdout (fdin, false);
-      char buf[sizeof ("/dev/fd/pipe:[2147483647]")];
-      __small_sprintf (buf, "/dev/fd/pipe:[%d]", (int) fdin);
+      char buf[sizeof ("/dev/fd/pipe:[9223372036854775807]")];
+      __small_sprintf (buf, "/dev/fd/pipe:[%D]", fhs[0]->get_ino ());
       fhs[0]->pc.set_posix (buf);
-      __small_sprintf (buf, "pipe:[%d]", (int) fdout);
+      __small_sprintf (buf, "pipe:[%D]", fhs[1]->get_ino ());
       fhs[1]->pc.set_posix (buf);
       fdin = fhs[0];
       fdout = fhs[1];
diff --git a/winsup/cygwin/release/2.4.0 b/winsup/cygwin/release/2.4.0
index ed035af..6247fb8 100644
--- a/winsup/cygwin/release/2.4.0
+++ b/winsup/cygwin/release/2.4.0
@@ -81,3 +81,6 @@ Bug Fixes
 - *Always* zero out descriptor arrays when returning from select due to
   timeout, per POSIX.
   Addresses: https://cygwin.com/ml/cygwin/2015-12/msg00332.html
+
+- Return unique inode numbers when calling stat/fstat on pipes and IP sockets.
+  Addresses: https://cygwin.com/ml/cygwin/2015-12/msg00310.html

Reply via email to