@@ -2156,6 +2156,78 @@ 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+ tmp_pathbuf tp;
2192+ /* we need a larger UNICODE_STRING MaximumLength than
2193+ get_nt_native_path allocates for the recursive copy */
2194+ UNICODE_STRING u_oldpath, u_newpath;
2195+ RtlCopyUnicodeString (tp.u_get (&u_oldpath), w_oldpath);
2196+ RtlCopyUnicodeString (tp.u_get (&u_newpath), w_newpath);
2197+ return recursiveCopy (&u_oldpath, &u_newpath,
2198+ u_oldpath.Length , u_newpath.Length );
2199+ }
2200+ else
2201+ {
2202+ bool isdirlink = false ;
2203+ if (win32_oldpath.issymlink () &&
2204+ win32_oldpath.is_known_reparse_point ())
2205+ {
2206+ /* Is there a better way to know this? */
2207+ DWORD attr = getfileattr (win32_oldpath.get_win32 (),
2208+ !!win32_oldpath.objcaseinsensitive ());
2209+ if (attr == INVALID_FILE_ATTRIBUTES)
2210+ {
2211+ __seterrno ();
2212+ return -1 ;
2213+ }
2214+ isdirlink = attr & FILE_ATTRIBUTE_DIRECTORY;
2215+ }
2216+ if (!CopyFileExW (w_oldpath->Buffer , w_newpath->Buffer ,
2217+ NULL , NULL , NULL ,
2218+ COPY_FILE_COPY_SYMLINK|
2219+ (isdirlink ? COPY_FILE_DIRECTORY : 0 )))
2220+ {
2221+ __seterrno ();
2222+ return -1 ;
2223+ }
2224+ else
2225+ {
2226+ return 0 ;
2227+ }
2228+ }
2229+ }
2230+
21592231int
21602232symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
21612233{
@@ -2223,6 +2295,13 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
22232295 case WSYM_nfs:
22242296 res = symlink_nfs (oldpath, win32_newpath);
22252297 __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;
22262305 case WSYM_native:
22272306 case WSYM_nativestrict:
22282307 res = symlink_native (oldpath, win32_newpath);
@@ -2239,6 +2318,7 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
22392318 wsym_type = WSYM_default;
22402319 fallthrough;
22412320 case WSYM_default:
2321+ handle_default:
22422322 if (win32_newpath.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS)
22432323 {
22442324 res = symlink_wsl (oldpath, win32_newpath);
@@ -2375,79 +2455,8 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
23752455 * sizeof (WCHAR);
23762456 cp += *plen;
23772457 }
2378- else
2458+ else /* wsym_type == WSYM_sysfile */
23792459 {
2380- if (wsym_type == WSYM_deepcopy)
2381- {
2382- path_conv win32_oldpath;
2383- /* The symlink target is relative to the directory in which the
2384- symlink gets created, not relative to the cwd. Therefore we
2385- have to mangle the path quite a bit before calling path_conv.*/
2386- mangle_symlink_target (oldpath, win32_newpath, win32_oldpath);
2387- if (win32_oldpath.error )
2388- {
2389- set_errno (win32_oldpath.error );
2390- __leave;
2391- }
2392- if (!win32_oldpath.isspecial ())
2393- {
2394- /* MSYS copy file instead make symlink */
2395- /* As a MSYS limitation, the source path must exist. */
2396- if (!win32_oldpath.exists ())
2397- {
2398- set_errno (ENOENT);
2399- __leave;
2400- }
2401-
2402- PUNICODE_STRING w_oldpath = win32_oldpath.get_nt_native_path ();
2403- PUNICODE_STRING w_newpath = win32_newpath.get_nt_native_path ();
2404- if (w_oldpath->Buffer [1 ] == L' ?' )
2405- w_oldpath->Buffer [1 ] = L' \\ ' ;
2406- if (w_newpath->Buffer [1 ] == L' ?' )
2407- w_newpath->Buffer [1 ] = L' \\ ' ;
2408- if (win32_oldpath.isdir ())
2409- {
2410- /* we need a larger UNICODE_STRING MaximumLength than
2411- get_nt_native_path allocates for the recursive copy */
2412- UNICODE_STRING u_oldpath, u_newpath;
2413- RtlCopyUnicodeString (tp.u_get (&u_oldpath), w_oldpath);
2414- RtlCopyUnicodeString (tp.u_get (&u_newpath), w_newpath);
2415- res = recursiveCopy (&u_oldpath, &u_newpath,
2416- u_oldpath.Length , u_newpath.Length );
2417- }
2418- else
2419- {
2420- bool isdirlink = false ;
2421- if (win32_oldpath.issymlink () &&
2422- win32_oldpath.is_known_reparse_point ())
2423- {
2424- /* Is there a better way to know this? */
2425- DWORD attr = getfileattr (win32_oldpath.get_win32 (),
2426- !!win32_oldpath.objcaseinsensitive ());
2427- if (attr == INVALID_FILE_ATTRIBUTES)
2428- {
2429- __seterrno ();
2430- __leave;
2431- }
2432- isdirlink = attr & FILE_ATTRIBUTE_DIRECTORY;
2433- }
2434- if (!CopyFileExW (w_oldpath->Buffer , w_newpath->Buffer ,
2435- NULL , NULL , NULL ,
2436- COPY_FILE_COPY_SYMLINK|
2437- (isdirlink ? COPY_FILE_DIRECTORY : 0 )))
2438- {
2439- __seterrno ();
2440- }
2441- else
2442- {
2443- res = 0 ;
2444- }
2445- }
2446- __leave;
2447- }
2448- }
2449-
2450- /* wsym_type == WSYM_sysfile */
24512460 /* Default technique creating a symlink. */
24522461 buf = tp.t_get ();
24532462 cp = stpcpy (buf, SYMLINK_COOKIE);
0 commit comments