232 lines
8.1 KiB
Diff
232 lines
8.1 KiB
Diff
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;
|