Skip to content

Commit 94ae14f

Browse files
committed
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. See also msys2#113/msys2#114.
1 parent 965fb2d commit 94ae14f

File tree

1 file changed

+90
-84
lines changed

1 file changed

+90
-84
lines changed

winsup/cygwin/path.cc

Lines changed: 90 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -2144,6 +2144,88 @@ symlink_wsl (const char *oldpath, path_conv &win32_newpath)
21442144
return 0;
21452145
}
21462146

2147+
int
2148+
symlink_deepcopy (const char *oldpath, path_conv &win32_newpath)
2149+
{
2150+
tmp_pathbuf tp;
2151+
path_conv win32_oldpath;
2152+
2153+
/* The symlink target is relative to the directory in which the
2154+
symlink gets created, not relative to the cwd. Therefore we
2155+
have to mangle the path quite a bit before calling path_conv.*/
2156+
if (isabspath (oldpath))
2157+
win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
2158+
else
2159+
{
2160+
size_t len = strrchr (win32_newpath.get_posix (), '/')
2161+
- win32_newpath.get_posix () + 1;
2162+
char *absoldpath = tp.t_get ();
2163+
stpcpy (stpncpy (absoldpath, win32_newpath.get_posix (), len),
2164+
oldpath);
2165+
win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
2166+
}
2167+
if (win32_oldpath.error)
2168+
{
2169+
set_errno (win32_oldpath.error);
2170+
return -1;
2171+
}
2172+
if (win32_oldpath.isspecial ())
2173+
return -2;
2174+
2175+
/* MSYS copy file instead make symlink */
2176+
/* As a MSYS limitation, the source path must exist. */
2177+
if (!win32_oldpath.exists ())
2178+
{
2179+
set_errno (ENOENT);
2180+
return -1;
2181+
}
2182+
2183+
PUNICODE_STRING w_oldpath = win32_oldpath.get_nt_native_path ();
2184+
PUNICODE_STRING w_newpath = win32_newpath.get_nt_native_path ();
2185+
if (w_oldpath->Buffer[1] == L'?')
2186+
w_oldpath->Buffer[1] = L'\\';
2187+
if (w_newpath->Buffer[1] == L'?')
2188+
w_newpath->Buffer[1] = L'\\';
2189+
if (win32_oldpath.isdir ())
2190+
{
2191+
/* we need a larger UNICODE_STRING MaximumLength than
2192+
get_nt_native_path allocates for the recursive copy */
2193+
UNICODE_STRING u_oldpath, u_newpath;
2194+
RtlCopyUnicodeString (tp.u_get (&u_oldpath), w_oldpath);
2195+
RtlCopyUnicodeString (tp.u_get (&u_newpath), w_newpath);
2196+
return recursiveCopy (&u_oldpath, &u_newpath,
2197+
u_oldpath.Length, u_newpath.Length);
2198+
}
2199+
else
2200+
{
2201+
bool isdirlink = false;
2202+
if (win32_oldpath.issymlink () &&
2203+
win32_oldpath.is_known_reparse_point ())
2204+
{
2205+
/* Is there a better way to know this? */
2206+
DWORD attr = getfileattr (win32_oldpath.get_win32 (),
2207+
!!win32_oldpath.objcaseinsensitive ());
2208+
if (attr == INVALID_FILE_ATTRIBUTES)
2209+
{
2210+
__seterrno ();
2211+
return -1;
2212+
}
2213+
isdirlink = attr & FILE_ATTRIBUTE_DIRECTORY;
2214+
}
2215+
if (!CopyFileExW (w_oldpath->Buffer, w_newpath->Buffer, NULL, NULL, NULL,
2216+
COPY_FILE_COPY_SYMLINK|
2217+
(isdirlink ? COPY_FILE_DIRECTORY : 0)))
2218+
{
2219+
__seterrno ();
2220+
return -1;
2221+
}
2222+
else
2223+
{
2224+
return 0;
2225+
}
2226+
}
2227+
}
2228+
21472229
int
21482230
symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
21492231
{
@@ -2212,6 +2294,13 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
22122294
case WSYM_nfs:
22132295
res = symlink_nfs (oldpath, win32_newpath);
22142296
__leave;
2297+
case WSYM_deepcopy:
2298+
res = symlink_deepcopy (oldpath, win32_newpath);
2299+
if (!res || res == -1)
2300+
__leave;
2301+
/* fall back to default symlink type */
2302+
wsym_type = WSYM_default;
2303+
goto handle_default;
22152304
case WSYM_native:
22162305
case WSYM_nativestrict:
22172306
res = symlink_native (oldpath, win32_newpath);
@@ -2228,6 +2317,7 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
22282317
wsym_type = WSYM_default;
22292318
fallthrough;
22302319
case WSYM_default:
2320+
handle_default:
22312321
if (win32_newpath.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS)
22322322
{
22332323
res = symlink_wsl (oldpath, win32_newpath);
@@ -2380,90 +2470,6 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
23802470
}
23812471
else /* wsym_type == WSYM_sysfile */
23822472
{
2383-
if (wsym_type == WSYM_deepcopy)
2384-
{
2385-
path_conv win32_oldpath;
2386-
/* The symlink target is relative to the directory in which the
2387-
symlink gets created, not relative to the cwd. Therefore we
2388-
have to mangle the path quite a bit before calling path_conv.*/
2389-
if (isabspath (oldpath))
2390-
win32_oldpath.check (oldpath,
2391-
PC_SYM_NOFOLLOW,
2392-
stat_suffixes);
2393-
else
2394-
{
2395-
len = strrchr (win32_newpath.get_posix (), '/')
2396-
- win32_newpath.get_posix () + 1;
2397-
char *absoldpath = tp.t_get ();
2398-
stpcpy (stpncpy (absoldpath, win32_newpath.get_posix (),
2399-
len),
2400-
oldpath);
2401-
win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW,
2402-
stat_suffixes);
2403-
}
2404-
if (win32_oldpath.error)
2405-
{
2406-
set_errno (win32_oldpath.error);
2407-
__leave;
2408-
}
2409-
if (!win32_oldpath.isspecial ())
2410-
{
2411-
/* MSYS copy file instead make symlink */
2412-
/* As a MSYS limitation, the source path must exist. */
2413-
if (!win32_oldpath.exists ())
2414-
{
2415-
set_errno (ENOENT);
2416-
__leave;
2417-
}
2418-
2419-
PUNICODE_STRING w_oldpath = win32_oldpath.get_nt_native_path ();
2420-
PUNICODE_STRING w_newpath = win32_newpath.get_nt_native_path ();
2421-
if (w_oldpath->Buffer[1] == L'?')
2422-
w_oldpath->Buffer[1] = L'\\';
2423-
if (w_newpath->Buffer[1] == L'?')
2424-
w_newpath->Buffer[1] = L'\\';
2425-
if (win32_oldpath.isdir ())
2426-
{
2427-
/* we need a larger UNICODE_STRING MaximumLength than
2428-
get_nt_native_path allocates for the recursive copy */
2429-
UNICODE_STRING u_oldpath, u_newpath;
2430-
RtlCopyUnicodeString (tp.u_get (&u_oldpath), w_oldpath);
2431-
RtlCopyUnicodeString (tp.u_get (&u_newpath), w_newpath);
2432-
res = recursiveCopy (&u_oldpath, &u_newpath,
2433-
u_oldpath.Length, u_newpath.Length);
2434-
}
2435-
else
2436-
{
2437-
bool isdirlink = false;
2438-
if (win32_oldpath.issymlink () &&
2439-
win32_oldpath.is_known_reparse_point ())
2440-
{
2441-
/* Is there a better way to know this? */
2442-
DWORD attr = getfileattr (win32_oldpath.get_win32 (),
2443-
!!win32_oldpath.objcaseinsensitive ());
2444-
if (attr == INVALID_FILE_ATTRIBUTES)
2445-
{
2446-
__seterrno ();
2447-
__leave;
2448-
}
2449-
isdirlink = attr & FILE_ATTRIBUTE_DIRECTORY;
2450-
}
2451-
if (!CopyFileExW (w_oldpath->Buffer, w_newpath->Buffer,
2452-
NULL, NULL, NULL,
2453-
COPY_FILE_COPY_SYMLINK|
2454-
(isdirlink ? COPY_FILE_DIRECTORY : 0)))
2455-
{
2456-
__seterrno ();
2457-
}
2458-
else
2459-
{
2460-
res = 0;
2461-
}
2462-
}
2463-
__leave;
2464-
}
2465-
}
2466-
24672473
/* Default technique creating a symlink. */
24682474
buf = tp.t_get ();
24692475
cp = stpcpy (buf, SYMLINK_COOKIE);

0 commit comments

Comments
 (0)