@@ -2156,6 +2156,77 @@ symlink_wsl (const char *oldpath, path_conv &win32_newpath)
21562156 return 0 ;
21572157}
21582158
2159+ int
2160+ symlink_deepcopy (const char *oldpath, path_conv &win32_newpath)
2161+ {
2162+ path_conv win32_oldpath;
2163+ /* The symlink target is relative to the directory in which the
2164+ symlink gets created, not relative to the cwd. Therefore we
2165+ have to mangle the path quite a bit before calling path_conv.*/
2166+ mangle_symlink_target (oldpath, win32_newpath, win32_oldpath);
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 ,
2216+ NULL , NULL , NULL ,
2217+ COPY_FILE_COPY_SYMLINK|
2218+ (isdirlink ? COPY_FILE_DIRECTORY : 0 )))
2219+ {
2220+ __seterrno ();
2221+ return -1 ;
2222+ }
2223+ else
2224+ {
2225+ return 0 ;
2226+ }
2227+ }
2228+ }
2229+
21592230int
21602231symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
21612232{
@@ -2224,6 +2295,13 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
22242295 case WSYM_nfs:
22252296 res = symlink_nfs (oldpath, win32_newpath);
22262297 __leave;
2298+ case WSYM_deepcopy:
2299+ res = symlink_deepcopy (oldpath, win32_newpath);
2300+ if (!res || res == -1 )
2301+ __leave;
2302+ /* fall back to default symlink type */
2303+ wsym_type = WSYM_default;
2304+ goto handle_default;
22272305 case WSYM_native:
22282306 case WSYM_nativestrict:
22292307 res = symlink_native (oldpath, win32_newpath);
@@ -2240,6 +2318,7 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
22402318 wsym_type = WSYM_default;
22412319 fallthrough;
22422320 case WSYM_default:
2321+ handle_default:
22432322 if (win32_newpath.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS)
22442323 {
22452324 res = symlink_wsl (oldpath, win32_newpath);
@@ -2376,79 +2455,8 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
23762455 * sizeof (WCHAR);
23772456 cp += *plen;
23782457 }
2379- else
2458+ else /* wsym_type == WSYM_sysfile */
23802459 {
2381- if (wsym_type == WSYM_deepcopy)
2382- {
2383- path_conv win32_oldpath;
2384- /* The symlink target is relative to the directory in which the
2385- symlink gets created, not relative to the cwd. Therefore we
2386- have to mangle the path quite a bit before calling path_conv.*/
2387- mangle_symlink_target (oldpath, win32_newpath, win32_oldpath);
2388- if (win32_oldpath.error )
2389- {
2390- set_errno (win32_oldpath.error );
2391- __leave;
2392- }
2393- if (!win32_oldpath.isspecial ())
2394- {
2395- /* MSYS copy file instead make symlink */
2396- /* As a MSYS limitation, the source path must exist. */
2397- if (!win32_oldpath.exists ())
2398- {
2399- set_errno (ENOENT);
2400- __leave;
2401- }
2402-
2403- PUNICODE_STRING w_oldpath = win32_oldpath.get_nt_native_path ();
2404- PUNICODE_STRING w_newpath = win32_newpath.get_nt_native_path ();
2405- if (w_oldpath->Buffer [1 ] == L' ?' )
2406- w_oldpath->Buffer [1 ] = L' \\ ' ;
2407- if (w_newpath->Buffer [1 ] == L' ?' )
2408- w_newpath->Buffer [1 ] = L' \\ ' ;
2409- if (win32_oldpath.isdir ())
2410- {
2411- /* we need a larger UNICODE_STRING MaximumLength than
2412- get_nt_native_path allocates for the recursive copy */
2413- UNICODE_STRING u_oldpath, u_newpath;
2414- RtlCopyUnicodeString (tp.u_get (&u_oldpath), w_oldpath);
2415- RtlCopyUnicodeString (tp.u_get (&u_newpath), w_newpath);
2416- res = recursiveCopy (&u_oldpath, &u_newpath,
2417- u_oldpath.Length , u_newpath.Length );
2418- }
2419- else
2420- {
2421- bool isdirlink = false ;
2422- if (win32_oldpath.issymlink () &&
2423- win32_oldpath.is_known_reparse_point ())
2424- {
2425- /* Is there a better way to know this? */
2426- DWORD attr = getfileattr (win32_oldpath.get_win32 (),
2427- !!win32_oldpath.objcaseinsensitive ());
2428- if (attr == INVALID_FILE_ATTRIBUTES)
2429- {
2430- __seterrno ();
2431- __leave;
2432- }
2433- isdirlink = attr & FILE_ATTRIBUTE_DIRECTORY;
2434- }
2435- if (!CopyFileExW (w_oldpath->Buffer , w_newpath->Buffer ,
2436- NULL , NULL , NULL ,
2437- COPY_FILE_COPY_SYMLINK|
2438- (isdirlink ? COPY_FILE_DIRECTORY : 0 )))
2439- {
2440- __seterrno ();
2441- }
2442- else
2443- {
2444- res = 0 ;
2445- }
2446- }
2447- __leave;
2448- }
2449- }
2450-
2451- /* wsym_type == WSYM_sysfile */
24522460 /* Default technique creating a symlink. */
24532461 buf = tp.t_get ();
24542462 cp = stpcpy (buf, SYMLINK_COOKIE);
0 commit comments