From 28d5757feb3049385071d96d55ed035dc485f07f Mon Sep 17 00:00:00 2001
From: Jeremy Drake <github@jdrake.com>
Date: Fri, 31 Jan 2025 16:00:56 -0800
Subject: [PATCH 45/N] fixup! Instead of creating Cygwin symlinks, use deep
 copy by default

Factor out deepcopy symlink to its own worker function, like wsl,
native, and nfs.  Move it up into the beginning switch with them, so the
fallback behavior is more obvious.
---
 winsup/cygwin/path.cc | 151 ++++++++++++++++++++++--------------------
 1 file changed, 80 insertions(+), 71 deletions(-)

diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 661a688..cf582c7 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -2072,6 +2072,79 @@ symlink_wsl (const char *oldpath, path_conv &win32_newpath)
   return 0;
 }
 
+int
+symlink_deepcopy (const char *oldpath, path_conv &win32_newpath)
+{
+  tmp_pathbuf tp;
+  path_conv src_path;
+
+  src_path.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+  if (src_path.error)
+    {
+      set_errno (src_path.error);
+      return -1;
+    }
+  if (src_path.isspecial ())
+    return -2;
+
+  /* MSYS copy file instead make symlink */
+  char * real_oldpath;
+  if (isabspath (oldpath))
+    strcpy (real_oldpath = tp.c_get (), oldpath);
+  else
+    /* Find the real source path, relative
+       to the directory of the destination */
+    {
+      /* Determine the character position of the last path component */
+      const char *newpath = win32_newpath.get_posix();
+      int pos = strlen (newpath);
+      while (--pos >= 0)
+	if (isdirsep (newpath[pos]))
+	  break;
+      /* Append the source path to the directory
+	 component of the destination */
+      if (pos+1+strlen(oldpath) >= MAX_PATH)
+	{
+	  set_errno(ENAMETOOLONG);
+	  return -1;
+	}
+      strcpy (real_oldpath = tp.c_get (), newpath);
+      strcpy (&real_oldpath[pos+1], oldpath);
+    }
+
+  /* As a MSYS limitation, the source path must exist. */
+  path_conv win32_oldpath;
+  win32_oldpath.check (real_oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+  if (!win32_oldpath.exists ())
+    {
+      set_errno (ENOENT);
+      return -1;
+    }
+
+  char *w_newpath;
+  char *w_oldpath;
+  stpcpy (w_newpath = tp.c_get (), win32_newpath.get_win32());
+  stpcpy (w_oldpath = tp.c_get (), win32_oldpath.get_win32());
+  if (win32_oldpath.isdir())
+    {
+      char *origpath;
+      strcpy (origpath = tp.c_get (), w_oldpath);
+      return recursiveCopy (w_oldpath, w_newpath, origpath);
+    }
+  else
+    {
+      if (!CopyFile (w_oldpath, w_newpath, FALSE))
+	{
+	  __seterrno ();
+	  return -1;
+	}
+      else
+	{
+	  return 0;
+	}
+    }
+}
+
 int
 symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
 {
@@ -2140,6 +2213,13 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
 	case WSYM_nfs:
 	  res = symlink_nfs (oldpath, win32_newpath);
 	  __leave;
+	case WSYM_deepcopy:
+	  res = symlink_deepcopy (oldpath, win32_newpath);
+	  if (!res || res == -1)
+	    __leave;
+	  /* fall back to sysfile symlink type */
+	  wsym_type = WSYM_sysfile;
+	  break;
 	case WSYM_native:
 	case WSYM_nativestrict:
 	  res = symlink_native (oldpath, win32_newpath);
@@ -2308,77 +2388,6 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
 	}
       else /* wsym_type == WSYM_sysfile */
 	{
-          if (wsym_type == WSYM_deepcopy)
-	    {
-	      path_conv src_path;
-	      src_path.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
-	      if (src_path.error)
-		{
-		  set_errno (src_path.error);
-		  __leave;
-		}
-	      if (!src_path.isspecial ())
-	        {
-		  /* MSYS copy file instead make symlink */
-
-		  char * real_oldpath;
-		  if (isabspath (oldpath))
-		    strcpy (real_oldpath = tp.c_get (), oldpath);
-		  else
-		    /* Find the real source path, relative
-		       to the directory of the destination */
-		    {
-		      /* Determine the character position of the last path component */
-		      const char *newpath = win32_newpath.get_posix();
-		      int pos = strlen (newpath);
-		      while (--pos >= 0)
-			if (isdirsep (newpath[pos]))
-			  break;
-		      /* Append the source path to the directory
-			 component of the destination */
-		      if (pos+1+strlen(oldpath) >= MAX_PATH)
-			{
-			  set_errno(ENAMETOOLONG);
-			  __leave;
-			}
-		      strcpy (real_oldpath = tp.c_get (), newpath);
-		      strcpy (&real_oldpath[pos+1], oldpath);
-		    }
-
-		  /* As a MSYS limitation, the source path must exist. */
-		  path_conv win32_oldpath;
-		  win32_oldpath.check (real_oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
-		  if (!win32_oldpath.exists ())
-		    {
-		      set_errno (ENOENT);
-		      __leave;
-		    }
-
-		  char *w_newpath;
-		  char *w_oldpath;
-		  stpcpy (w_newpath = tp.c_get (), win32_newpath.get_win32());
-		  stpcpy (w_oldpath = tp.c_get (), win32_oldpath.get_win32());
-		  if (win32_oldpath.isdir())
-		    {
-		      char *origpath;
-		      strcpy (origpath = tp.c_get (), w_oldpath);
-		      res = recursiveCopy (w_oldpath, w_newpath, origpath);
-		    }
-		  else
-		    {
-		      if (!CopyFile (w_oldpath, w_newpath, FALSE))
-			{
-			  __seterrno ();
-			}
-		      else
-			{
-			  res = 0;
-			}
-		    }
-		  __leave;
-		}
-	    }
-
 	  /* Default technique creating a symlink. */
 	  buf = tp.t_get ();
 	  cp = stpcpy (buf, SYMLINK_COOKIE);
