See https://github.com/msys2/msys2-runtime/pull/63 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
238 lines
7.1 KiB
Diff
238 lines
7.1 KiB
Diff
From 2f41ba83a1949dfdea9a15d9736792fe0e4ca417 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 f746841..296c890 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 48fb312..72e8f8f 100644
|
|
--- a/winsup/cygwin/globals.cc
|
|
+++ b/winsup/cygwin/globals.cc
|
|
@@ -59,6 +59,7 @@ enum winsym_t
|
|
WSYM_nativestrict,
|
|
WSYM_nfs,
|
|
WSYM_sysfile,
|
|
+ WSYM_deepcopy
|
|
};
|
|
|
|
exit_states NO_COPY exit_state;
|
|
@@ -72,7 +73,7 @@ bool ignore_case_with_glob;
|
|
bool pipe_byte;
|
|
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 5a3aa9b..f4a0881 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
|
|
@@ -2215,6 +2298,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);
|
|
--
|
|
2.33.0
|
|
|