MSYS2-packages/msys2-runtime/0007-Instead-of-creating-Cygwin-symlinks-use-deep-copy-by.patch
2023-02-15 17:56:15 +01:00

235 lines
7.1 KiB
Diff

From aa291fa865b4e7c7461d80adabe557f3dd9b6b83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?=
=?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= <alexey.pawlow@gmail.com>
Date: Sun, 14 Apr 2019 21:47:21 +0300
Subject: [PATCH 07/N] Instead of creating Cygwin symlinks, use deep copy by
default
The new `winsymlinks` mode `deepcopy` (which is made the default) lets
calls to `symlink()` create (deep) copies of the source file/directory.
This is necessary because unlike Cygwin, MSYS2 does not try to be its
own little ecosystem that lives its life separate from regular Win32
programs: the latter have _no idea_ about Cygwin-emulated symbolic links
(i.e. system files whose contents start with `!<symlink>\xff\xfe` and
the remainder consists of the NUL-terminated, UTF-16LE-encoded symlink
target).
To support Cygwin-style symlinks, the new mode `sysfile` is introduced.
Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
winsup/cygwin/environ.cc | 4 +
winsup/cygwin/globals.cc | 3 +-
winsup/cygwin/path.cc | 154 +++++++++++++++++++++++++++++++++++++++
3 files changed, 160 insertions(+), 1 deletion(-)
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 568bb34..02b47ad 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -88,6 +88,10 @@ set_winsymlinks (const char *buf)
else if (ascii_strncasematch (buf, "native", 6))
allow_winsymlinks = ascii_strcasematch (buf + 6, "strict")
? WSYM_nativestrict : WSYM_native;
+ else if (ascii_strncasematch (buf, "deepcopy", 8))
+ allow_winsymlinks = WSYM_deepcopy;
+ else
+ allow_winsymlinks = WSYM_sysfile;
}
/* The structure below is used to set up an array which is used to
diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc
index aef4a68..cd907b7 100644
--- a/winsup/cygwin/globals.cc
+++ b/winsup/cygwin/globals.cc
@@ -57,6 +57,7 @@ enum winsym_t
WSYM_nativestrict,
WSYM_nfs,
WSYM_sysfile,
+ WSYM_deepcopy
};
exit_states NO_COPY exit_state;
@@ -70,7 +71,7 @@ bool ignore_case_with_glob;
bool pipe_byte = true; /* Default to byte mode so that C# programs work. */
bool reset_com;
bool wincmdln;
-winsym_t allow_winsymlinks = WSYM_default;
+winsym_t allow_winsymlinks = WSYM_deepcopy;
bool disable_pcon;
bool NO_COPY in_forkee;
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 2ca749c..3378b6d 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1682,6 +1682,89 @@ conv_path_list (const char *src, char *dst, size_t size,
/********************** Symbolic Link Support **************************/
+/*
+ Create a deep copy of src as dst, while avoiding descending in origpath.
+*/
+static int
+recursiveCopy (char * src, char * dst, const char * origpath)
+{
+ WIN32_FIND_DATA dHfile;
+ HANDLE dH = INVALID_HANDLE_VALUE;
+ BOOL findfiles;
+ int srcpos = strlen (src);
+ int dstpos = strlen (dst);
+ int res = -1;
+
+ debug_printf("recursiveCopy (%s, %s)", src, dst);
+
+ /* Create the destination directory */
+ if (!CreateDirectoryEx (src, dst, NULL))
+ {
+ debug_printf("CreateDirectoryEx(%s, %s, 0) failed", src, dst);
+ __seterrno ();
+ goto done;
+ }
+ /* Descend into the source directory */
+ if (srcpos + 2 >= MAX_PATH || dstpos + 1 >= MAX_PATH)
+ {
+ set_errno (ENAMETOOLONG);
+ goto done;
+ }
+ strcat (src, "\\*");
+ strcat (dst, "\\");
+ dH = FindFirstFile (src, &dHfile);
+ debug_printf("dHfile(1): %s", dHfile.cFileName);
+ findfiles = FindNextFile (dH, &dHfile);
+ debug_printf("dHfile(2): %s", dHfile.cFileName);
+ findfiles = FindNextFile (dH, &dHfile);
+ while (findfiles)
+ {
+ /* Append the directory item filename to both source and destination */
+ int filelen = strlen (dHfile.cFileName);
+ debug_printf("dHfile(3): %s", dHfile.cFileName);
+ if (srcpos + 1 + filelen >= MAX_PATH ||
+ dstpos + 1 + filelen >= MAX_PATH)
+ {
+ set_errno (ENAMETOOLONG);
+ goto done;
+ }
+ strcpy (&src[srcpos+1], dHfile.cFileName);
+ strcpy (&dst[dstpos+1], dHfile.cFileName);
+ debug_printf("%s -> %s", src, dst);
+ if (dHfile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ /* Recurse into the child directory */
+ debug_printf("%s <-> %s", src, origpath);
+ if (strcmp (src, origpath)) // avoids endless recursion
+ if (recursiveCopy (src, dst, origpath))
+ goto done;
+ }
+ else
+ {
+ /* Just copy the file */
+ if (!CopyFile (src, dst, FALSE))
+ {
+ __seterrno ();
+ goto done;
+ }
+ }
+ findfiles = FindNextFile (dH, &dHfile);
+ }
+ if (GetLastError() != ERROR_NO_MORE_FILES)
+ {
+ __seterrno ();
+ goto done;
+ }
+ res = 0;
+
+done:
+
+ if (dH != INVALID_HANDLE_VALUE)
+ FindClose (dH);
+
+ return res;
+}
+
/* Create a symlink from FROMPATH to TOPATH. */
extern "C" int
@@ -2219,6 +2302,77 @@ 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.isdevice () && !src_path.is_fs_special ())
+ {
+ /* 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);