[newlib-cygwin] Cygwin: Move O_TMPFILE to bin and allow linkat by handle

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


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

commit 7dbe307e389b916ad4f34ea3c3258049abad2d2c
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Sat Jan 5 22:15:58 2019 +0100

    Cygwin: Move O_TMPFILE to bin and allow linkat by handle
    
    Along the same lines as the previous patch: By reopening an
    O_TMPFILE by handle, we can now move the file to the bin at
    open time and thus free'ing up the parent dir and *still*
    open the file as /proc/PID/fd/DESCRIPTOR by linkat(2).

Diff:
---
 winsup/cygwin/fhandler.h          |  1 +
 winsup/cygwin/fhandler_process.cc | 82 +++++++++++++++++++++++++++++++++++++++
 winsup/cygwin/syscalls.cc         |  8 +++-
 3 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 74eb1d7..1c751c1 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2555,6 +2555,7 @@ class fhandler_process: public fhandler_proc
   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 ();
 
diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc
index 0fad96f..a523148 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -399,6 +399,88 @@ err_out:
   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/syscalls.cc b/winsup/cygwin/syscalls.cc
index 2fb4bc4..9f43512 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1484,6 +1484,10 @@ open (const char *unix_path, int flags, ...)
       else if ((fh->is_fs_special () && fh->device_access_denied (flags))
 	       || !fh->open_with_arch (flags, mode & 07777))
 	__leave;		/* errno already set */
+      /* Move O_TMPFILEs to the bin to avoid blocking the parent dir. */
+      if ((flags & O_TMPFILE) && !fh->pc.isremote ())
+	try_to_bin (fh->pc, fh->get_handle (), DELETE,
+		    FILE_OPEN_FOR_BACKUP_INTENT);
       fd = fh;
       if (fd <= 2)
 	set_std_handle (fd);
@@ -4791,7 +4795,9 @@ linkat (int olddirfd, const char *oldpathname,
 	__leave;
       if (flags & AT_SYMLINK_FOLLOW)
 	{
-	  path_conv old_name (oldpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
+	  path_conv old_name (oldpath,
+			      PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_PROCFD | PC_POSIX,
+			      stat_suffixes);
 	  if (old_name.error)
 	    {
 	      set_errno (old_name.error);



More information about the Cygwin-cvs mailing list