From 3de55006728b87f8cae7364fc08f539579b18414 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Thu, 30 Jan 2025 14:39:18 -0800 Subject: [PATCH] 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. The COPY_FILE_DIRECTORY flag is documented as only supported on Windows 10 build 19041 and later, but without it copying a directory symlink fails anyway. --- winsup/cygwin/path.cc | 58 +++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 23e02fb565..7722ad86f2 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,34 @@ 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) - { - /* Recurse into the child directory */ - debug_printf ("%S <-> %W", src, origpath); + 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 ((dHfile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !isdirlink) + { + /* 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, - COPY_FILE_COPY_SYMLINK)) - { - __seterrno (); - goto done; - } - } + { + /* Just copy the file */ + if (!CopyFileExW (src->Buffer, dst->Buffer, NULL, NULL, NULL, + COPY_FILE_COPY_SYMLINK| + (isdirlink ? COPY_FILE_DIRECTORY : 0))) + { + __seterrno (); + goto done; + } + } findfiles = FindNextFileW (dH, &dHfile); } if (GetLastError() != ERROR_NO_MORE_FILES) @@ -2314,7 +2324,7 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice) } else /* wsym_type == WSYM_sysfile */ { - if (wsym_type == WSYM_deepcopy) + if (wsym_type == WSYM_deepcopy) { path_conv win32_oldpath; /* The symlink target is relative to the directory in which the @@ -2341,7 +2351,7 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice) __leave; } if (!win32_oldpath.isspecial ()) - { + { /* MSYS copy file instead make symlink */ /* As a MSYS limitation, the source path must exist. */ if (!win32_oldpath.exists ()) @@ -2361,7 +2371,7 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice) 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 */ + 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); @@ -2369,9 +2379,15 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice) } else { + /* I don't know if there's a better way to know this */ + DWORD attr = getfileattr (win32_oldpath.get_win32 (), + win32_oldpath.obcaseinsensitive ()); + bool isdirlink = attr != INVALID_FILE_ATTRIBUTES && + (attr & FILE_ATTRIBUTE_DIRECTORY); if (!CopyFileExW (w_oldpath->Buffer, w_newpath->Buffer, NULL, NULL, NULL, - COPY_FILE_COPY_SYMLINK)) + COPY_FILE_COPY_SYMLINK| + (isdirlink ? COPY_FILE_DIRECTORY : 0))) { __seterrno (); }