[PATCH 1/2] Implicitly support the /dev/fd symlink and friends

Johannes Schindelin johannes.schindelin@gmx.de
Mon Feb 21 13:36:37 GMT 2022


Bash has a very convenient feature that is called process substitution
(e.g. `diff -u <(seq 0 10) <(seq 1 11)`). To make this work, Bash
requires the `/dev/fd` symlink to exist, and Cygwin therefore creates
this symlink (together with the `stdin`, `stdout` and `stderr` ones)
upon start-up.

This strategy is incompatible with the idea of providing a subset of
Cygwin in a `.zip` file (because there is no standard way to represent
symlinks in `.zip` files, and besides, older Windows versions would
potentially lack support for them anyway).

That type of `.zip` file is what Git for Windows wants to use, though,
bundling a minimal subset for third-party applications in MinGit (see
https://github.com/git-for-windows/git/wiki/MinGit for details).

Let's side-step this problem completely by creating those symlinks
implicitly, similar to the way `/dev/` is populated with special
devices.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 winsup/cygwin/Makefile.am        |  1 +
 winsup/cygwin/devices.h          |  3 +-
 winsup/cygwin/devices.in         |  4 +++
 winsup/cygwin/dtable.cc          |  3 ++
 winsup/cygwin/fhandler.h         | 28 +++++++++++++++++
 winsup/cygwin/fhandler_dev_fd.cc | 53 ++++++++++++++++++++++++++++++++
 6 files changed, 91 insertions(+), 1 deletion(-)
 create mode 100644 winsup/cygwin/fhandler_dev_fd.cc

diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am
index 2b8e87fcd0..c8936354b8 100644
--- a/winsup/cygwin/Makefile.am
+++ b/winsup/cygwin/Makefile.am
@@ -230,6 +230,7 @@ DLL_FILES= \
 	fhandler_console.cc \
 	fhandler_cygdrive.cc \
 	fhandler_dev.cc \
+	fhandler_dev_fd.cc \
 	fhandler_disk_file.cc \
 	fhandler_dsp.cc \
 	fhandler_fifo.cc \
diff --git a/winsup/cygwin/devices.h b/winsup/cygwin/devices.h
index 4310f435fe..fbbde6ab9c 100644
--- a/winsup/cygwin/devices.h
+++ b/winsup/cygwin/devices.h
@@ -70,6 +70,7 @@ enum fh_devices
   FH_NETDRIVE= FHDEV (DEV_VIRTFS_MAJOR, 194),
   FH_DEV     = FHDEV (DEV_VIRTFS_MAJOR, 193),
   FH_CYGDRIVE= FHDEV (DEV_VIRTFS_MAJOR, 192),
+  FH_DEV_FD  = FHDEV (DEV_VIRTFS_MAJOR, 191),

   FH_SIGNALFD= FHDEV (DEV_VIRTFS_MAJOR, 13),
   FH_TIMERFD = FHDEV (DEV_VIRTFS_MAJOR, 14),
@@ -436,7 +437,7 @@ extern const _device dev_fs_storage;
 #define isprocsys_dev(devn) (devn == FH_PROCSYS)

 #define isvirtual_dev(devn) \
-  (isproc_dev (devn) || devn == FH_CYGDRIVE || devn == FH_NETDRIVE)
+  (isproc_dev (devn) || devn == FH_CYGDRIVE || devn == FH_NETDRIVE || devn == FH_DEV_FD)

 #define iscons_dev(n) \
   ((device::major ((dev_t) (n)) == DEV_CONS_MAJOR) \
diff --git a/winsup/cygwin/devices.in b/winsup/cygwin/devices.in
index f33510eb7e..7506dfe9cb 100644
--- a/winsup/cygwin/devices.in
+++ b/winsup/cygwin/devices.in
@@ -175,6 +175,10 @@ const _device dev_error_storage =
 "/dev/fd%(0-15)d", BRACK(FHDEV(DEV_FLOPPY_MAJOR, {$1})), "\\Device\\Floppy{$1}", exists_ntdev, S_IFBLK
 "/dev/scd%(0-15)d", BRACK(FHDEV(DEV_CDROM_MAJOR, {$1})), "\\Device\\CdRom{$1}", exists_ntdev, S_IFBLK
 "/dev/sr%(0-15)d", BRACK(FHDEV(DEV_CDROM_MAJOR, {$1})), "\\Device\\CdRom{$1}", exists_ntdev, S_IFBLK
+"/dev/fd", BRACK(FH_DEV_FD), "/proc/self/fd", exists, S_IFLNK
+"/dev/stdin", BRACK(FH_DEV_FD), "/proc/self/fd/0", exists, S_IFLNK
+"/dev/stdout", BRACK(FH_DEV_FD), "/proc/self/fd/1", exists, S_IFLNK
+"/dev/stderr", BRACK(FH_DEV_FD), "/proc/self/fd/2", exists, S_IFLNK
 %other	{return	NULL;}
 %%
 #undef BRACK
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index ce5f6411b3..28d7697259 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -579,6 +579,9 @@ fh_alloc (path_conv& pc)
 	case FH_DEV:
 	  fh = cnew (fhandler_dev);
 	  break;
+	case FH_DEV_FD:
+	  fh = cnew (fhandler_dev_fd);
+	  break;
 	case FH_CYGDRIVE:
 	  fh = cnew (fhandler_cygdrive);
 	  break;
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index f764eccd33..6c1b2a8025 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -3009,6 +3009,33 @@ class fhandler_procnet: public fhandler_proc
   }
 };

+class fhandler_dev_fd: public fhandler_virtual
+{
+ public:
+  fhandler_dev_fd ();
+  virtual_ftype_t exists();
+
+  int __reg2 fstat (struct stat *buf);
+  bool fill_filebuf ();
+
+  fhandler_dev_fd (void *) {}
+
+  virtual void copy_from (fhandler_base *x)
+  {
+    pc.free_strings ();
+    *this = *reinterpret_cast<fhandler_dev_fd *> (x);
+    _copy_from_reset_helper ();
+  }
+
+  virtual fhandler_dev_fd *clone (cygheap_types malloc_type = HEAP_FHANDLER)
+  {
+    void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_fd));
+    fhandler_dev_fd *fh = new (ptr) fhandler_dev_fd (ptr);
+    fh->copy_from (this);
+    return fh;
+  }
+};
+
 class fhandler_signalfd : public fhandler_base
 {
   sigset_t sigset;
@@ -3208,6 +3235,7 @@ typedef union
   char __dev_raw[sizeof (fhandler_dev_raw)];
   char __dev_tape[sizeof (fhandler_dev_tape)];
   char __dev_zero[sizeof (fhandler_dev_zero)];
+  char __dev_fd[sizeof (fhandler_dev_fd)];
   char __disk_file[sizeof (fhandler_disk_file)];
   char __fifo[sizeof (fhandler_fifo)];
   char __netdrive[sizeof (fhandler_netdrive)];
diff --git a/winsup/cygwin/fhandler_dev_fd.cc b/winsup/cygwin/fhandler_dev_fd.cc
new file mode 100644
index 0000000000..6462838317
--- /dev/null
+++ b/winsup/cygwin/fhandler_dev_fd.cc
@@ -0,0 +1,53 @@
+/* fhandler_process_fd.cc: fhandler for the /dev/{fd,std{in,out,err}} symlinks
+
+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 "path.h"
+#include "fhandler.h"
+
+fhandler_dev_fd::fhandler_dev_fd ():
+  fhandler_virtual ()
+{
+}
+
+virtual_ftype_t
+fhandler_dev_fd::exists ()
+{
+  return virt_symlink;
+}
+
+int __reg2
+fhandler_dev_fd::fstat (struct stat *buf)
+{
+  const char *path = get_name ();
+  debug_printf ("fstat (%s)", path);
+
+  fhandler_base::fstat (buf);
+
+  buf->st_mode = S_IFLNK | STD_RBITS | S_IWUSR | S_IWGRP | S_IWOTH | STD_XBITS;
+  buf->st_ino = get_ino ();
+
+  return 0;
+}
+
+bool
+fhandler_dev_fd::fill_filebuf ()
+{
+  const char *path = get_name ();
+  debug_printf ("fill_filebuf (%s)", path);
+
+  const char *native = get_native_name ();
+  if (!native)
+    {
+      return false;
+    }
+
+  free(filebuf);
+  filebuf = cstrdup (native);
+  return true;
+}
--
2.35.1




More information about the Cygwin-patches mailing list