msys2-runtime: add deepcopy symlink improvements

msys2/msys2-runtime#256
This commit is contained in:
Jeremy Drake
2025-02-06 10:16:25 -08:00
committed by Christoph Reiter
parent b11b4ed895
commit e5cebcadcc
9 changed files with 1005 additions and 4 deletions

View File

@@ -0,0 +1,189 @@
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);

View File

@@ -0,0 +1,231 @@
From 4606ccb4588d0993ca2351f3ed9e0e15f180e590 Mon Sep 17 00:00:00 2001
From: Jeremy Drake <github@jdrake.com>
Date: Thu, 30 Jan 2025 13:30:25 -0800
Subject: [PATCH 46/N] fixup! Instead of creating Cygwin symlinks, use deep
copy by default
Use unicode APIs instead of ANSI, for better handling of long paths and
unicode characters.
Use FindFirstFileExW with FindExInfoBasic (because recursiveCopy doesn't
care about short file names) and FIND_FIRST_EX_LARGE_FETCH (for better
performance).
Use CopyFileExW with COPY_FILE_COPY_SYMLINK, so native symlinks act like
sys and lnk file symlinks (they're copied as links instead of their
target).
---
winsup/cygwin/path.cc | 144 +++++++++++++++++++++---------------------
1 file changed, 72 insertions(+), 72 deletions(-)
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index cf582c7..9671e8f 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1693,69 +1693,75 @@ conv_path_list (const char *src, char *dst, size_t size,
Create a deep copy of src as dst, while avoiding descending in origpath.
*/
static int
-recursiveCopy (char * src, char * dst, const char * origpath)
+recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
{
- WIN32_FIND_DATA dHfile;
+ WIN32_FIND_DATAW dHfile;
HANDLE dH = INVALID_HANDLE_VALUE;
BOOL findfiles;
- int srcpos = strlen (src);
- int dstpos = strlen (dst);
+ int srcpos = src->Length;
+ int dstpos = dst->Length;
int res = -1;
- debug_printf("recursiveCopy (%s, %s)", src, dst);
+ debug_printf ("recursiveCopy (%S, %S)", src, dst);
/* Create the destination directory */
- if (!CreateDirectoryEx (src, dst, NULL))
+ if (!CreateDirectoryExW (src->Buffer, dst->Buffer, NULL))
{
- debug_printf("CreateDirectoryEx(%s, %s, 0) failed", src, dst);
+ debug_printf ("CreateDirectoryExW(%S, %S, 0) failed", src, dst);
__seterrno ();
goto done;
}
/* Descend into the source directory */
- if (srcpos + 2 >= MAX_PATH || dstpos + 1 >= MAX_PATH)
+ if (src->Buffer[(src->Length - 1) / sizeof (WCHAR)] != L'\\')
{
- set_errno (ENAMETOOLONG);
- goto done;
+ RtlAppendUnicodeToString (src, L"\\*");
+ }
+ else
+ {
+ RtlAppendUnicodeToString (src, L"*");
+ srcpos -= sizeof (WCHAR);
}
- 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);
+ if (dst->Buffer[(dst->Length - 1) / sizeof (WCHAR)] != L'\\')
+ RtlAppendUnicodeToString (dst, L"\\");
+ else
+ dstpos -= sizeof (WCHAR);
+
+ dH = FindFirstFileExW (src->Buffer, FindExInfoBasic, &dHfile,
+ FindExSearchNameMatch, NULL,
+ FIND_FIRST_EX_LARGE_FETCH);
+ debug_printf ("dHfile(1): %W", dHfile.cFileName);
+ findfiles = FindNextFileW (dH, &dHfile);
+ debug_printf ("dHfile(2): %W", dHfile.cFileName);
+ findfiles = FindNextFileW (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);
+ debug_printf ("dHfile(3): %W", dHfile.cFileName);
+ src->Length = srcpos + sizeof (WCHAR);
+ dst->Length = dstpos + sizeof (WCHAR);
+ RtlAppendUnicodeToString (src, dHfile.cFileName);
+ RtlAppendUnicodeToString (dst, 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
+ debug_printf ("%S <-> %W", src, origpath);
+ // avoids endless recursion
+ if (wcsncmp (src->Buffer, origpath, src->Length / sizeof (WCHAR)))
if (recursiveCopy (src, dst, origpath))
goto done;
}
else
{
/* Just copy the file */
- if (!CopyFile (src, dst, FALSE))
+ if (!CopyFileExW (src->Buffer, dst->Buffer, NULL, NULL, NULL,
+ COPY_FILE_COPY_SYMLINK))
{
__seterrno ();
goto done;
}
}
- findfiles = FindNextFile (dH, &dHfile);
+ findfiles = FindNextFileW (dH, &dHfile);
}
if (GetLastError() != ERROR_NO_MORE_FILES)
{
@@ -2076,64 +2082,58 @@ int
symlink_deepcopy (const char *oldpath, path_conv &win32_newpath)
{
tmp_pathbuf tp;
- path_conv src_path;
+ path_conv win32_oldpath;
- src_path.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
- if (src_path.error)
+ /* The symlink target is relative to the directory in which the
+ symlink gets created, not relative to the cwd. Therefore we
+ have to mangle the path quite a bit before calling path_conv.*/
+ if (isabspath (oldpath))
+ win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+ else
{
- set_errno (src_path.error);
+ size_t len = strrchr (win32_newpath.get_posix (), '/')
+ - win32_newpath.get_posix () + 1;
+ char *absoldpath = tp.t_get ();
+ stpcpy (stpncpy (absoldpath, win32_newpath.get_posix (), len),
+ oldpath);
+ win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+ }
+ if (win32_oldpath.error)
+ {
+ set_errno (win32_oldpath.error);
return -1;
}
- if (src_path.isspecial ())
+ if (win32_oldpath.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())
+ PUNICODE_STRING w_oldpath = win32_oldpath.get_nt_native_path ();
+ PUNICODE_STRING w_newpath = win32_newpath.get_nt_native_path ();
+ if (w_oldpath->Buffer[1] == L'?')
+ w_oldpath->Buffer[1] = L'\\';
+ if (w_newpath->Buffer[1] == L'?')
+ w_newpath->Buffer[1] = L'\\';
+ if (win32_oldpath.isdir ())
{
- char *origpath;
- strcpy (origpath = tp.c_get (), w_oldpath);
- return recursiveCopy (w_oldpath, w_newpath, origpath);
+ PWCHAR origpath = win32_oldpath.get_wide_win32_path (tp.w_get ());
+ /* we need a larger UNICODE_STRING MaximumLength than
+ get_nt_native_path allocates for the recursive copy */
+ UNICODE_STRING u_oldpath, u_newpath;
+ RtlCopyUnicodeString (tp.u_get (&u_oldpath), w_oldpath);
+ RtlCopyUnicodeString (tp.u_get (&u_newpath), w_newpath);
+ return recursiveCopy (&u_oldpath, &u_newpath, origpath);
}
else
{
- if (!CopyFile (w_oldpath, w_newpath, FALSE))
+ if (!CopyFileExW (w_oldpath->Buffer, w_newpath->Buffer,
+ NULL, NULL, NULL, COPY_FILE_COPY_SYMLINK))
{
__seterrno ();
return -1;

View File

@@ -0,0 +1,136 @@
From 4fa86d82cb1bb74c86014f4f4331c19262bc7fd9 Mon Sep 17 00:00:00 2001
From: Jeremy Drake <github@jdrake.com>
Date: Thu, 30 Jan 2025 14:39:18 -0800
Subject: [PATCH 47/N] fixup! Instead of creating Cygwin symlinks, use deep
copy by default
Don't attempt to recurse into directory symlinks, but instead copy them
as symlinks.
Use CreateDirectoryEx to copy directory reparse points (directory
symlinks or junctions). This seems to work at least back to 8.1, unlike
the COPY_FILE_DIRECTORY flag, which was introduced in 19041.
---
winsup/cygwin/path.cc | 86 ++++++++++++++++++++++++++++++++-----------
1 file changed, 65 insertions(+), 21 deletions(-)
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 9671e8f..dfbbdaa 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1735,6 +1735,7 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
findfiles = FindNextFileW (dH, &dHfile);
while (findfiles)
{
+ bool isdirlink = false;
/* Append the directory item filename to both source and destination */
debug_printf ("dHfile(3): %W", dHfile.cFileName);
src->Length = srcpos + sizeof (WCHAR);
@@ -1742,25 +1743,44 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
RtlAppendUnicodeToString (src, dHfile.cFileName);
RtlAppendUnicodeToString (dst, dHfile.cFileName);
debug_printf ("%S -> %S", src, dst);
- if (dHfile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ if ((dHfile.dwFileAttributes &
+ (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT)) ==
+ (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT))
+ {
+ /* this sucks hard */
+ path_conv pc (src, PC_SYM_NOFOLLOW|PC_SYM_NOFOLLOW_REP);
+ isdirlink = pc.issymlink ();
+ }
+ if (isdirlink)
{
- /* Recurse into the child directory */
- debug_printf ("%S <-> %W", src, origpath);
+ /* CreateDirectoryEx seems to "copy" directory reparse points, which
+ CopyFileEx can only do with a flag introduced in 19041. */
+ if (!CreateDirectoryExW (src->Buffer, dst->Buffer, NULL))
+ {
+ debug_printf ("CreateDirectoryExW(%S, %S, 0) failed", src, dst);
+ __seterrno ();
+ goto done;
+ }
+ }
+ else if (dHfile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ /* Recurse into the child directory */
+ debug_printf ("%S <-> %W", src, origpath);
// avoids endless recursion
- if (wcsncmp (src->Buffer, origpath, src->Length / sizeof (WCHAR)))
- if (recursiveCopy (src, dst, origpath))
- goto done;
- }
+ if (wcsncmp (src->Buffer, origpath, src->Length / sizeof (WCHAR)))
+ if (recursiveCopy (src, dst, origpath))
+ goto done;
+ }
else
- {
- /* Just copy the file */
- if (!CopyFileExW (src->Buffer, dst->Buffer, NULL, NULL, NULL,
+ {
+ /* Just copy the file */
+ if (!CopyFileExW (src->Buffer, dst->Buffer, NULL, NULL, NULL,
COPY_FILE_COPY_SYMLINK))
- {
- __seterrno ();
- goto done;
- }
- }
+ {
+ __seterrno ();
+ goto done;
+ }
+ }
findfiles = FindNextFileW (dH, &dHfile);
}
if (GetLastError() != ERROR_NO_MORE_FILES)
@@ -2132,17 +2152,41 @@ symlink_deepcopy (const char *oldpath, path_conv &win32_newpath)
}
else
{
- if (!CopyFileExW (w_oldpath->Buffer, w_newpath->Buffer,
- NULL, NULL, NULL, COPY_FILE_COPY_SYMLINK))
+ bool isdirlink = false;
+ if (win32_oldpath.issymlink () &&
+ win32_oldpath.is_known_reparse_point ())
{
- __seterrno ();
- return -1;
+ /* Is there a better way to know this? */
+ DWORD attr = getfileattr (win32_oldpath.get_win32 (),
+ !!win32_oldpath.objcaseinsensitive ());
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ {
+ __seterrno ();
+ return -1;
+ }
+ isdirlink = attr & FILE_ATTRIBUTE_DIRECTORY;
}
- else
+ if (isdirlink)
+ {
+ /* CreateDirectoryEx seems to "copy" directory reparse points, which
+ CopyFileEx can only do with a flag introduced in 19041. */
+ if (!CreateDirectoryExW (w_oldpath->Buffer, w_newpath->Buffer, NULL))
+ {
+ debug_printf ("CreateDirectoryExW(%S, %S, 0) failed", w_oldpath,
+ w_newpath);
+ __seterrno ();
+ return -1;
+ }
+ }
+ else if (!CopyFileExW (w_oldpath->Buffer, w_newpath->Buffer, NULL, NULL,
+ NULL, COPY_FILE_COPY_SYMLINK))
{
- return 0;
+ __seterrno ();
+ return -1;
}
}
+
+ return 0;
}
int

View File

@@ -0,0 +1,57 @@
From ed1c4f3322f115bd9a8e9306014d50bc41ad467b Mon Sep 17 00:00:00 2001
From: Jeremy Drake <github@jdrake.com>
Date: Thu, 30 Jan 2025 17:45:16 -0800
Subject: [PATCH 48/N] fixup! Instead of creating Cygwin symlinks, use deep
copy by default
Don't assume the first two entries are always `.` and `..`. On the root
of a volume, those don't seem to be present.
---
winsup/cygwin/path.cc | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index dfbbdaa..1e6baef 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1697,7 +1697,6 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
{
WIN32_FIND_DATAW dHfile;
HANDLE dH = INVALID_HANDLE_VALUE;
- BOOL findfiles;
int srcpos = src->Length;
int dstpos = dst->Length;
int res = -1;
@@ -1729,15 +1728,15 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
dH = FindFirstFileExW (src->Buffer, FindExInfoBasic, &dHfile,
FindExSearchNameMatch, NULL,
FIND_FIRST_EX_LARGE_FETCH);
- debug_printf ("dHfile(1): %W", dHfile.cFileName);
- findfiles = FindNextFileW (dH, &dHfile);
- debug_printf ("dHfile(2): %W", dHfile.cFileName);
- findfiles = FindNextFileW (dH, &dHfile);
- while (findfiles)
+ do
{
bool isdirlink = false;
+ debug_printf ("dHfile: %W", dHfile.cFileName);
+ if (dHfile.cFileName[0] == L'.' &&
+ (!dHfile.cFileName[1] ||
+ (dHfile.cFileName[1] == L'.' && !dHfile.cFileName[2])))
+ continue;
/* Append the directory item filename to both source and destination */
- debug_printf ("dHfile(3): %W", dHfile.cFileName);
src->Length = srcpos + sizeof (WCHAR);
dst->Length = dstpos + sizeof (WCHAR);
RtlAppendUnicodeToString (src, dHfile.cFileName);
@@ -1781,8 +1780,9 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
goto done;
}
}
- findfiles = FindNextFileW (dH, &dHfile);
}
+ while (FindNextFileW (dH, &dHfile));
+
if (GetLastError() != ERROR_NO_MORE_FILES)
{
__seterrno ();

View File

@@ -0,0 +1,97 @@
From b581e48de68ede7ac406b4c03d297822ce9e4613 Mon Sep 17 00:00:00 2001
From: Jeremy Drake <github@jdrake.com>
Date: Thu, 30 Jan 2025 22:00:06 -0800
Subject: [PATCH 49/N] fixup! Instead of creating Cygwin symlinks, use deep
copy by default
Add error handling.
---
winsup/cygwin/path.cc | 42 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 37 insertions(+), 5 deletions(-)
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 1e6baef..56f9d6a 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1697,6 +1697,7 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
{
WIN32_FIND_DATAW dHfile;
HANDLE dH = INVALID_HANDLE_VALUE;
+ NTSTATUS status;
int srcpos = src->Length;
int dstpos = dst->Length;
int res = -1;
@@ -1713,21 +1714,37 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
/* Descend into the source directory */
if (src->Buffer[(src->Length - 1) / sizeof (WCHAR)] != L'\\')
{
- RtlAppendUnicodeToString (src, L"\\*");
+ status = RtlAppendUnicodeToString (src, L"\\*");
}
else
{
- RtlAppendUnicodeToString (src, L"*");
+ status = RtlAppendUnicodeToString (src, L"*");
srcpos -= sizeof (WCHAR);
}
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ goto done;
+ }
if (dst->Buffer[(dst->Length - 1) / sizeof (WCHAR)] != L'\\')
- RtlAppendUnicodeToString (dst, L"\\");
+ status = RtlAppendUnicodeToString (dst, L"\\");
else
dstpos -= sizeof (WCHAR);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ goto done;
+ }
dH = FindFirstFileExW (src->Buffer, FindExInfoBasic, &dHfile,
FindExSearchNameMatch, NULL,
FIND_FIRST_EX_LARGE_FETCH);
+ if (dH == INVALID_HANDLE_VALUE)
+ {
+ __seterrno ();
+ goto done;
+ }
+
do
{
bool isdirlink = false;
@@ -1739,8 +1756,18 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
/* Append the directory item filename to both source and destination */
src->Length = srcpos + sizeof (WCHAR);
dst->Length = dstpos + sizeof (WCHAR);
- RtlAppendUnicodeToString (src, dHfile.cFileName);
- RtlAppendUnicodeToString (dst, dHfile.cFileName);
+ status = RtlAppendUnicodeToString (src, dHfile.cFileName);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ goto done;
+ }
+ status = RtlAppendUnicodeToString (dst, dHfile.cFileName);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ goto done;
+ }
debug_printf ("%S -> %S", src, dst);
if ((dHfile.dwFileAttributes &
(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT)) ==
@@ -1748,6 +1775,11 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
{
/* this sucks hard */
path_conv pc (src, PC_SYM_NOFOLLOW|PC_SYM_NOFOLLOW_REP);
+ if (pc.error)
+ {
+ set_errno (pc.error);
+ goto done;
+ }
isdirlink = pc.issymlink ();
}
if (isdirlink)

View File

@@ -0,0 +1,155 @@
From e5effeec3bb1bbfd4849b03c92a7cc2ff3b146a7 Mon Sep 17 00:00:00 2001
From: Jeremy Drake <github@jdrake.com>
Date: Fri, 31 Jan 2025 10:33:27 -0800
Subject: [PATCH 50/N] fixup! Instead of creating Cygwin symlinks, use deep
copy by default
Allocate one WIN32_FIND_DATAW on the heap for the whole recursiveCopy,
to avoid running out of stack space before hitting path limit.
Move the path_conv object into its own function to avoid it being in the
recursion's stack frame.
---
winsup/cygwin/path.cc | 61 ++++++++++++++++++++++++++++---------------
1 file changed, 40 insertions(+), 21 deletions(-)
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 56f9d6a..4a9d500 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1689,18 +1689,37 @@ conv_path_list (const char *src, char *dst, size_t size,
/********************** Symbolic Link Support **************************/
+static int
+recursiveCopyCheckSymlink(PUNICODE_STRING src, bool& isdirlink)
+{
+ path_conv pc (src, PC_SYM_NOFOLLOW|PC_SYM_NOFOLLOW_REP);
+ if (pc.error)
+ {
+ set_errno (pc.error);
+ return -1;
+ }
+ isdirlink = pc.issymlink ();
+ return 0;
+}
+
/*
Create a deep copy of src as dst, while avoiding descending in origpath.
*/
static int
-recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
+recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath, PWIN32_FIND_DATAW dHfile = NULL)
{
- WIN32_FIND_DATAW dHfile;
HANDLE dH = INVALID_HANDLE_VALUE;
NTSTATUS status;
int srcpos = src->Length;
int dstpos = dst->Length;
int res = -1;
+ bool freedHfile = false;
+
+ if (!dHfile)
+ {
+ dHfile = (PWIN32_FIND_DATAW) cmalloc_abort (HEAP_STR, sizeof (*dHfile));
+ freedHfile = true;
+ }
debug_printf ("recursiveCopy (%S, %S)", src, dst);
@@ -1736,7 +1755,7 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
goto done;
}
- dH = FindFirstFileExW (src->Buffer, FindExInfoBasic, &dHfile,
+ dH = FindFirstFileExW (src->Buffer, FindExInfoBasic, dHfile,
FindExSearchNameMatch, NULL,
FIND_FIRST_EX_LARGE_FETCH);
if (dH == INVALID_HANDLE_VALUE)
@@ -1748,39 +1767,36 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
do
{
bool isdirlink = false;
- debug_printf ("dHfile: %W", dHfile.cFileName);
- if (dHfile.cFileName[0] == L'.' &&
- (!dHfile.cFileName[1] ||
- (dHfile.cFileName[1] == L'.' && !dHfile.cFileName[2])))
+ debug_printf ("dHfile: %W", dHfile->cFileName);
+ if (dHfile->cFileName[0] == L'.' &&
+ (!dHfile->cFileName[1] ||
+ (dHfile->cFileName[1] == L'.' && !dHfile->cFileName[2])))
continue;
/* Append the directory item filename to both source and destination */
src->Length = srcpos + sizeof (WCHAR);
dst->Length = dstpos + sizeof (WCHAR);
- status = RtlAppendUnicodeToString (src, dHfile.cFileName);
+ status = RtlAppendUnicodeToString (src, dHfile->cFileName);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
goto done;
}
- status = RtlAppendUnicodeToString (dst, dHfile.cFileName);
+ status = RtlAppendUnicodeToString (dst, dHfile->cFileName);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
goto done;
}
debug_printf ("%S -> %S", src, dst);
- if ((dHfile.dwFileAttributes &
+ if ((dHfile->dwFileAttributes &
(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT)) ==
(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT))
{
- /* this sucks hard */
- path_conv pc (src, PC_SYM_NOFOLLOW|PC_SYM_NOFOLLOW_REP);
- if (pc.error)
- {
- set_errno (pc.error);
- goto done;
- }
- isdirlink = pc.issymlink ();
+ /* I was really hoping to avoid using path_conv in the recursion,
+ but maybe putting it in its own function will prevent it from
+ taking up space in the stack frame */
+ if (recursiveCopyCheckSymlink (src, isdirlink))
+ goto done;
}
if (isdirlink)
{
@@ -1793,13 +1809,13 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
goto done;
}
}
- else if (dHfile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ else if (dHfile->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
/* Recurse into the child directory */
debug_printf ("%S <-> %W", src, origpath);
// avoids endless recursion
if (wcsncmp (src->Buffer, origpath, src->Length / sizeof (WCHAR)))
- if (recursiveCopy (src, dst, origpath))
+ if (recursiveCopy (src, dst, origpath, dHfile))
goto done;
}
else
@@ -1813,7 +1829,7 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath)
}
}
}
- while (FindNextFileW (dH, &dHfile));
+ while (FindNextFileW (dH, dHfile));
if (GetLastError() != ERROR_NO_MORE_FILES)
{
@@ -1827,6 +1843,9 @@ done:
if (dH != INVALID_HANDLE_VALUE)
FindClose (dH);
+ if (freedHfile)
+ cfree (dHfile);
+
return res;
}

View File

@@ -0,0 +1,63 @@
From cf77c3eff0ddd18e9182928e346a70618064a281 Mon Sep 17 00:00:00 2001
From: Jeremy Drake <github@jdrake.com>
Date: Fri, 31 Jan 2025 12:27:42 -0800
Subject: [PATCH 51/N] fixup! Instead of creating Cygwin symlinks, use deep
copy by default
avoid recursing into dst as well as src. Given we only ever append to
either, their original lengths should be sufficient, rather than copies
of them.
---
winsup/cygwin/path.cc | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 4a9d500..373aec9 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1706,7 +1706,8 @@ recursiveCopyCheckSymlink(PUNICODE_STRING src, bool& isdirlink)
Create a deep copy of src as dst, while avoiding descending in origpath.
*/
static int
-recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath, PWIN32_FIND_DATAW dHfile = NULL)
+recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, USHORT origsrclen,
+ USHORT origdstlen, PWIN32_FIND_DATAW dHfile = NULL)
{
HANDLE dH = INVALID_HANDLE_VALUE;
NTSTATUS status;
@@ -1812,11 +1813,15 @@ recursiveCopy (PUNICODE_STRING src, PUNICODE_STRING dst, PCWSTR origpath, PWIN32
else if (dHfile->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
/* Recurse into the child directory */
- debug_printf ("%S <-> %W", src, origpath);
- // avoids endless recursion
- if (wcsncmp (src->Buffer, origpath, src->Length / sizeof (WCHAR)))
- if (recursiveCopy (src, dst, origpath, dHfile))
+ /* avoids endless recursion */
+ if (src->Length <= origsrclen ||
+ !wcsncmp (src->Buffer, dst->Buffer, origdstlen / sizeof (WCHAR)))
+ {
+ set_errno (ELOOP);
goto done;
+ }
+ if (recursiveCopy (src, dst, origsrclen, origdstlen, dHfile))
+ goto done;
}
else
{
@@ -2193,13 +2198,13 @@ symlink_deepcopy (const char *oldpath, path_conv &win32_newpath)
w_newpath->Buffer[1] = L'\\';
if (win32_oldpath.isdir ())
{
- PWCHAR origpath = win32_oldpath.get_wide_win32_path (tp.w_get ());
/* we need a larger UNICODE_STRING MaximumLength than
get_nt_native_path allocates for the recursive copy */
UNICODE_STRING u_oldpath, u_newpath;
RtlCopyUnicodeString (tp.u_get (&u_oldpath), w_oldpath);
RtlCopyUnicodeString (tp.u_get (&u_newpath), w_newpath);
- return recursiveCopy (&u_oldpath, &u_newpath, origpath);
+ return recursiveCopy (&u_oldpath, &u_newpath,
+ u_oldpath.Length, u_newpath.Length);
}
else
{

View File

@@ -0,0 +1,49 @@
From 19b50e4bbb3f833ed43d16741d15735bd5fe682b Mon Sep 17 00:00:00 2001
From: Jeremy Drake <github@jdrake.com>
Date: Tue, 4 Feb 2025 11:05:18 -0800
Subject: [PATCH 52/N] amend! Instead of creating Cygwin symlinks, use deep
copy by default
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>
Co-authored-by: Jeremy Drake <github@jdrake.com>
---
winsup/cygwin/path.cc | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 373aec9..33eb644 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -2160,6 +2160,10 @@ symlink_deepcopy (const char *oldpath, path_conv &win32_newpath)
tmp_pathbuf tp;
path_conv win32_oldpath;
+ /* **BEGIN** replace this with
+ resolve_symlink_target (oldpath, win32_newpath. win32_oldpath);
+ when rebasing over 5a706ff0fceb83fd1fe7f072fc28a741fdde65f2
+ (probably Cygwin 3.6) */
/* The symlink target is relative to the directory in which the
symlink gets created, not relative to the cwd. Therefore we
have to mangle the path quite a bit before calling path_conv.*/
@@ -2174,6 +2178,7 @@ symlink_deepcopy (const char *oldpath, path_conv &win32_newpath)
oldpath);
win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
}
+ /* **END** */
if (win32_oldpath.error)
{
set_errno (win32_oldpath.error);

View File

@@ -4,7 +4,7 @@
pkgbase=msys2-runtime
pkgname=('msys2-runtime' 'msys2-runtime-devel')
pkgver=3.5.7
pkgrel=1
pkgrel=2
pkgdesc="Cygwin POSIX emulation engine"
arch=('x86_64')
url="https://www.cygwin.com/"
@@ -72,7 +72,15 @@ source=('msys2-runtime'::git://sourceware.org/git/newlib-cygwin.git#tag=cygwin-$
0041-cygthread-suspend-thread-before-terminating.patch
0042-Cygwin-revert-use-of-CancelSyncronousIo-on-wait_thre.patch
0043-Cygwin-cache-IsWow64Process2-host-arch-in-wincap.patch
0044-Cygwin-uname-add-host-machine-tag-to-sysname.patch)
0044-Cygwin-uname-add-host-machine-tag-to-sysname.patch
0045-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch
0046-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch
0047-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch
0048-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch
0049-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch
0050-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch
0051-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch
0052-amend-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch)
sha256sums=('e78e129eed8e2dd4a2600fe6df8cb6f3beb9dca786574823ed55951adecb7064'
'87d86c95008274731cf560d929ae5fb319d962591303b2690e11bfd60f4818e7'
'c6d091cb51440638eb9fc59b35ba40f2b63e9e32a31a56c51a2aaec2445aa88e'
@@ -117,7 +125,15 @@ sha256sums=('e78e129eed8e2dd4a2600fe6df8cb6f3beb9dca786574823ed55951adecb7064'
'94c5ed183b0fd2d9efaecd839bee8d25621c01d8ba2f32d3a98e958936c73fec'
'e1d1779b1c14897ee8543f14d54383bf9313e407cde74da217fbfe21c92ac4fc'
'6c6e23ece7fa055d27289bad39d0007623303673316c593feba15fb6cfaf2b8a'
'9aefd148000fbfaebfd8a490cd980efb43e9a6b000002df11be6a4eacfb43365')
'9aefd148000fbfaebfd8a490cd980efb43e9a6b000002df11be6a4eacfb43365'
'734b7f1e1264834817a42ebe83cf2bda06417e0ebb1090c6eecd267f420de043'
'f7a54cd5328c909f907dfc1766a3192b22fd80195504f8989c8c0dc220da8a24'
'73243bedf4918b8e9bc0f033444c95d1eac89824c4efacab33b19d383a6799fd'
'26318aa2f84e7f28400695cd79b71c499dda72043a50483e6263115bc8ec53fd'
'0d438fbe0aa08c01a9f10547ced185d42d3583ff835dbb768dd687249138fb99'
'e24911a237886d043959ccf64a4f862e91b0d9e322f200d255355040aae3ea16'
'54e01260a3b481f2e178f2d603442d206b497b554a530c85d365febb11b12488'
'086916ec5e3f038d6b815f268880bdda39b574efaa1c9a53fdc08ce46a57ba20')
# Helper macros to help make tasks easier #
apply_patch_with_msg() {
@@ -198,7 +214,15 @@ prepare() {
0041-cygthread-suspend-thread-before-terminating.patch \
0042-Cygwin-revert-use-of-CancelSyncronousIo-on-wait_thre.patch \
0043-Cygwin-cache-IsWow64Process2-host-arch-in-wincap.patch \
0044-Cygwin-uname-add-host-machine-tag-to-sysname.patch
0044-Cygwin-uname-add-host-machine-tag-to-sysname.patch \
0045-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch \
0046-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch \
0047-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch \
0048-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch \
0049-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch \
0050-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch \
0051-fixup-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch \
0052-amend-Instead-of-creating-Cygwin-symlinks-use-deep-c.patch
}
build() {