[newlib-cygwin] Cygwin: introduce fhandler_process_fd and add stat(2) handling

Corinna Vinschen corinna@sourceware.org
Sun Jan 6 19:42:00 GMT 2019


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

commit 7aca27b4fe553657d057dce90de13be97068fd4a
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Sun Jan 6 20:18:14 2019 +0100

    Cygwin: introduce fhandler_process_fd and add stat(2) handling
    
    move special fd symlink code into own fhandler_process_fd class
    to simplify further additions to /proc/PID/fd/DESCRIPTOR symlink
    handling.
    
    Add a method to handle stat(2) on such a proc fd symlink by handle.
    This allows correct reply from stat(2) if the target file has been
    deleted.  This eventually fixes `awk -f /dev/fd/3 3<<eof'.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/Makefile.in            |   1 +
 winsup/cygwin/dtable.cc              |   4 +-
 winsup/cygwin/fhandler.h             |  32 ++++++-
 winsup/cygwin/fhandler_process.cc    | 160 -----------------------------------
 winsup/cygwin/fhandler_process_fd.cc | 153 +++++++++++++++++++++++++++++++++
 winsup/cygwin/syscalls.cc            |   3 +-
 6 files changed, 189 insertions(+), 164 deletions(-)

diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index fb0195f..75c73bf 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -288,6 +288,7 @@ DLL_OFILES:= \
 	fhandler_nodevice.o \
 	fhandler_proc.o \
 	fhandler_process.o \
+	fhandler_process_fd.o \
 	fhandler_procnet.o \
 	fhandler_procsys.o \
 	fhandler_procsysvipc.o \
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index 0ebeef0..780deb5 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -552,9 +552,11 @@ fh_alloc (path_conv& pc)
 	  fh = cnew (fhandler_registry);
 	  break;
 	case FH_PROCESS:
-	case FH_PROCESSFD:
 	  fh = cnew (fhandler_process);
 	  break;
+	case FH_PROCESSFD:
+	  fh = cnew (fhandler_process_fd);
+	  break;
 	case FH_PROCNET:
 	  fh = cnew (fhandler_procnet);
 	  break;
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 1c751c1..e32c219 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2545,6 +2545,7 @@ class fhandler_registry: public fhandler_proc
 class pinfo;
 class fhandler_process: public fhandler_proc
 {
+ protected:
   pid_t pid;
   virtual_ftype_t fd_type;
  public:
@@ -2554,8 +2555,6 @@ class fhandler_process: public fhandler_proc
   int closedir (DIR *);
   int __reg3 readdir (DIR *, dirent *);
   int open (int flags, mode_t mode = 0);
-  virtual fhandler_base *fd_reopen (int);
-  int __reg2 link (const char *);
   int __reg2 fstat (struct stat *buf);
   bool fill_filebuf ();
 
@@ -2577,6 +2576,34 @@ class fhandler_process: public fhandler_proc
   }
 };
 
+class fhandler_process_fd : public fhandler_process
+{
+  fhandler_base *fetch_fh (HANDLE &);
+
+ public:
+  fhandler_process_fd () : fhandler_process () {}
+  fhandler_process_fd (void *) {}
+
+  virtual fhandler_base *fd_reopen (int);
+  int __reg2 fstat (struct stat *buf);
+  virtual int __reg2 link (const char *);
+
+  void copyto (fhandler_base *x)
+  {
+    x->pc.free_strings ();
+    *reinterpret_cast<fhandler_process_fd *> (x) = *this;
+    x->reset (this);
+  }
+
+  fhandler_process_fd *clone (cygheap_types malloc_type = HEAP_FHANDLER)
+  {
+    void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_process_fd));
+    fhandler_process_fd *fh = new (ptr) fhandler_process_fd (ptr);
+    copyto (fh);
+    return fh;
+  }
+};
+
 class fhandler_procnet: public fhandler_proc
 {
   pid_t pid;
@@ -2638,6 +2665,7 @@ typedef union
   char __pipe[sizeof (fhandler_pipe)];
   char __proc[sizeof (fhandler_proc)];
   char __process[sizeof (fhandler_process)];
+  char __process_fd[sizeof (fhandler_process_fd)];
   char __procnet[sizeof (fhandler_procnet)];
   char __procsys[sizeof (fhandler_procsys)];
   char __procsysvipc[sizeof (fhandler_procsysvipc)];
diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc
index a523148..24ef7d0 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -321,166 +321,6 @@ out:
   return res;
 }
 
-fhandler_base *
-fhandler_process::fd_reopen (int flags)
-{
-  const char *path;
-  char *e;
-  int fd;
-  HANDLE proc = NULL;
-  HANDLE hdl = NULL;
-  fhandler_base *fh = NULL;
-
-  path = get_name () + proc_len + 1;
-  pid = strtoul (path, &e, 10);
-  path = e + 4;
-  fd = strtoul (path, &e, 10);
-  if (e == path || *e != '\0')
-    {
-      set_errno (ENOENT);
-      return NULL;
-    }
-
-  if (pid == myself->pid)
-    {
-      cygheap_fdget cfd (fd);
-      if (cfd < 0)
-	return NULL;
-      fh = build_fh_pc (cfd->pc);
-      if (!fh)
-	goto err_out;
-      fh->set_io_handle (cfd->get_handle ());
-    }
-  else
-    {
-      size_t size;
-      path_conv pc;
-
-      pinfo p (pid);
-      if (!p)
-	{
-	  set_errno (ENOENT);
-	  return NULL;
-	}
-      if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId)))
-	{
-	  __seterrno ();
-	  return NULL;
-	}
-      void *buf = p->file_pathconv (fd, size);
-      if (size == 0)
-	{
-	  set_errno (EPERM);
-	  goto err_out;
-	}
-      hdl = pc.deserialize (buf);
-      if (!DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl,
-			    0, FALSE, DUPLICATE_SAME_ACCESS))
-	{
-	  __seterrno ();
-	  hdl = NULL;
-	  goto err_out;
-	}
-      fh = build_fh_pc (pc);
-      if (!fh)
-	goto err_out;
-      fh->set_io_handle (hdl);
-    }
-  if (!fh->open_with_arch (flags, 0))
-    {
-      delete fh;
-      fh = NULL;
-    }
-err_out:
-  if (hdl)
-    CloseHandle (hdl);
-  if (proc)
-    CloseHandle (proc);
-  return fh;
-}
-
-int
-fhandler_process::link (const char *newpath)
-{
-  const char *path;
-  int fd;
-  char *e;
-
-  path = get_name () + proc_len + 1;
-  pid = atoi (path);
-  while (*path != 0 && !isdirsep (*path))
-    path++;
-  if (*path == 0)
-    goto err_out;
-
-  virt_tab_t *entry;
-  entry = virt_tab_search (path + 1, true, process_tab, PROCESS_LINK_COUNT);
-  if (!entry || entry->fhandler != FH_PROCESSFD)
-    goto err_out;
-  if (path[3] != '/' || path[4] == '\0')
-    goto err_out;
-
-  fd = strtoul (path + 4, &e, 10);
-  if (fd < 0 || e == path + 4 || (*e != '/' && *e != '\0'))
-    goto err_out;
-  if (pid == myself->pid)
-    {
-      cygheap_fdget cfd (fd);
-      if (cfd < 0)
-	goto err_out;
-      return cfd->link (newpath);
-    }
-  else
-    {
-      HANDLE proc;
-      size_t size;
-      void *buf;
-      path_conv pc;
-      HANDLE hdl;
-      fhandler_base *fh = NULL;
-      int ret = -1;
-
-      pinfo p (pid);
-      if (!p)
-	{
-	  set_errno (ENOENT);
-	  return -1;
-	}
-      if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId)))
-	goto err_out;
-      buf = p->file_pathconv (fd, size);
-      if (size == 0)
-	{
-	  set_errno (EPERM);
-	  goto err_out_close_proc;
-	}
-      hdl = pc.deserialize (buf);
-      if (!DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl,
-			    0, FALSE, DUPLICATE_SAME_ACCESS))
-	{
-	  __seterrno ();
-	  goto err_out_close_proc;
-	}
-      fh = build_fh_pc (pc);
-      if (!fh)
-	goto err_out_close_dup;
-
-      fh->set_io_handle (hdl);
-      ret = fh->link (newpath);
-      delete fh;
-
-err_out_close_dup:
-      CloseHandle (hdl);
-err_out_close_proc:
-      CloseHandle (proc);
-      return ret;
-    }
-
-err_out:
-  set_errno (EPERM);
-  return -1;
-}
-
 struct process_fd_t {
   const char *path;
   _pinfo *p;
diff --git a/winsup/cygwin/fhandler_process_fd.cc b/winsup/cygwin/fhandler_process_fd.cc
new file mode 100644
index 0000000..06d37c0
--- /dev/null
+++ b/winsup/cygwin/fhandler_process_fd.cc
@@ -0,0 +1,153 @@
+/* fhandler_process_fd.cc: fhandler for /proc/<pid>/fd/<desc> operations
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/cygwin.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "fhandler_virtual.h"
+#include "pinfo.h"
+#include "shared_info.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "ntdll.h"
+#include "cygtls.h"
+#include "mount.h"
+#include "tls_pbuf.h"
+#include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <ctype.h>
+
+
+fhandler_base *
+fhandler_process_fd::fetch_fh (HANDLE &out_hdl)
+{
+  const char *path;
+  char *e;
+  int fd;
+  HANDLE proc;
+  HANDLE hdl = NULL;
+  path_conv pc;
+
+  path = get_name () + proc_len + 1;
+  pid = strtoul (path, &e, 10);
+  path = e + 4;
+  fd = strtoul (path, &e, 10);
+
+  out_hdl = NULL;
+  if (pid == myself->pid)
+    {
+      cygheap_fdget cfd (fd, true);
+      if (cfd < 0)
+	return NULL;
+      proc = GetCurrentProcess ();
+      pc << cfd->pc;
+      hdl = cfd->get_handle ();
+    }
+  else
+    {
+      pinfo p (pid);
+      if (!p)
+	{
+	  set_errno (ENOENT);
+	  return NULL;
+	}
+      proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId);
+      if (!proc)
+	{
+	  __seterrno ();
+	  return NULL;
+	}
+      size_t size;
+      void *buf = p->file_pathconv (fd, size);
+      if (size == 0)
+	{
+	  set_errno (EPERM);
+	  CloseHandle (proc);
+	  return NULL;
+	}
+      hdl = pc.deserialize (buf);
+    }
+  BOOL ret = DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl,
+			 0, FALSE, DUPLICATE_SAME_ACCESS);
+  if (proc != GetCurrentProcess ())
+    CloseHandle (proc);
+  if (!ret)
+    {
+      __seterrno ();
+      CloseHandle (hdl);
+      return NULL;
+    }
+  fhandler_base *fh = build_fh_pc (pc);
+  if (!fh)
+    {
+      CloseHandle (hdl);
+      return NULL;
+    }
+  out_hdl = hdl;
+  return fh;
+}
+
+fhandler_base *
+fhandler_process_fd::fd_reopen (int flags)
+{
+  fhandler_base *fh;
+  HANDLE hdl;
+
+  fh = fetch_fh (hdl);
+  if (!fh)
+    return NULL;
+  fh->set_io_handle (hdl);
+  int ret = fh->open_with_arch (flags, 0);
+  CloseHandle (hdl);
+  if (!ret)
+    {
+      delete fh;
+      fh = NULL;
+    }
+  return fh;
+}
+
+int __reg2
+fhandler_process_fd::fstat (struct stat *statbuf)
+{
+  if (!pc.follow_fd_symlink ())
+    return fhandler_process::fstat (statbuf);
+
+  fhandler_base *fh;
+  HANDLE hdl;
+
+  fh = fetch_fh (hdl);
+  if (!fh)
+    return -1;
+  fh->set_io_handle (hdl);
+  int ret = fh->fstat (statbuf);
+  CloseHandle (hdl);
+  delete fh;
+  return ret;
+}
+
+int
+fhandler_process_fd::link (const char *newpath)
+{
+  fhandler_base *fh;
+  HANDLE hdl;
+
+  fh = fetch_fh (hdl);
+  if (!fh)
+    return -1;
+  fh->set_io_handle (hdl);
+  int ret = fh->link (newpath);
+  CloseHandle (hdl);
+  delete fh;
+  return ret;
+}
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 60f66a6..5bb33bf 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -2005,7 +2005,8 @@ extern "C" int
 stat64 (const char *__restrict name, struct stat *__restrict buf)
 {
   syscall_printf ("entering");
-  path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE,
+  path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE
+		      | PC_SYM_NOFOLLOW_PROCFD,
 		stat_suffixes);
   return stat_worker (pc, buf);
 }



More information about the Cygwin-cvs mailing list