@@ -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+
21472229int
21482230symlink_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