Skip to content

Commit

Permalink
winsymlinks: add a mode preferring native symlinks with a deepcopy fa…
Browse files Browse the repository at this point in the history
…llback

When native symlinks are available, it is a shame to create deep copies
by default.

However, since there are many scenarios where symlinks are not available
(e.g. when running on FAT, or on older Windows versions, or when
Developer Mode is not enabled), we've got to have a fallback.

In the regular Cygwin world, it is legitimate to fall back to WSL
symlinks and/or to the system file emulation (where a file is created
that is marked with the "system" attribute and with content that adheres
to a specific, magic form that is recognized specifically by the Cygwin
runtime).

However, in the world of MSYS2, the assumption is that the result of the
operation should be as interoperable with regular Win32 programs as
possible. Hence the default to "deepcopy".

As a "best of both worlds" mode, let's implement one that tries to
create native symlinks by default, and if that fails, uses the
"deepcopy" method as a fallback.

This addresses #113.

Signed-off-by: Johannes Schindelin <[email protected]>
  • Loading branch information
dscho committed Jul 24, 2024
1 parent f0d57f8 commit b8e842e
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 2 deletions.
2 changes: 2 additions & 0 deletions winsup/cygwin/environ.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ set_winsymlinks (const char *buf)
? WSYM_nativestrict : WSYM_native;
else if (ascii_strncasematch (buf, "deepcopy", 8))
allow_winsymlinks = WSYM_deepcopy;
else if (ascii_strncasematch (buf, "nativeordeepcopy", 8))
allow_winsymlinks = WSYM_native_or_deepcopy;
else
allow_winsymlinks = WSYM_sysfile;
}
Expand Down
3 changes: 2 additions & 1 deletion winsup/cygwin/globals.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ enum winsym_t
WSYM_nativestrict,
WSYM_nfs,
WSYM_sysfile,
WSYM_deepcopy
WSYM_deepcopy,
WSYM_native_or_deepcopy
};

exit_states NO_COPY exit_state;
Expand Down
10 changes: 10 additions & 0 deletions winsup/cygwin/path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2110,6 +2110,9 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
else if ((wsym_type == WSYM_native || wsym_type == WSYM_nativestrict)
&& !(win32_newpath.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS))
wsym_type = WSYM_default;
else if (wsym_type == WSYM_native_or_deepcopy
&& !(win32_newpath.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS))
wsym_type = WSYM_deepcopy;

/* Attach .lnk suffix when shortcut is requested. */
if (wsym_type == WSYM_lnk && !win32_newpath.exists ()
Expand Down Expand Up @@ -2144,6 +2147,7 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
__leave;
case WSYM_native:
case WSYM_nativestrict:
case WSYM_native_or_deepcopy:
res = symlink_native (oldpath, win32_newpath);
if (!res)
__leave;
Expand All @@ -2154,6 +2158,12 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
__seterrno ();
__leave;
}
/* With deepcopy fall back? Let's do that, then */
if (res == -1 && wsym_type == WSYM_native_or_deepcopy)
{
wsym_type = WSYM_deepcopy;
break;
}
/* Otherwise, fall back to default symlink type. */
wsym_type = WSYM_default;
fallthrough;
Expand Down
10 changes: 9 additions & 1 deletion winsup/doc/cygwinenv.xml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ back to the parent process.</para>
</listitem>

<listitem>
<para><envar>winsymlinks:{lnk,native,nativestrict,sys,deepcopy}</envar></para>
<para><envar>winsymlinks:{lnk,native,nativestrict,sys,deepcopy,nativeordeepcopy}</envar></para>

<itemizedlist mark="square">
<listitem>
Expand Down Expand Up @@ -141,6 +141,14 @@ the source directory will be copied recursively). This mode makes a trade-off
between compatibility and interoperability with Win32 programs, favoring the
latter.</para>
</listitem>

<listitem>
<para>If set to <literal>winsymlinks:nativeordeepcopy</literal> Cygwin creates
symlinks as native Windows symlinks if supported (i.e. on file systems
supporting symbolic links, and when the current user is permitted to create
symbolic links, e.g. in Windows 10's "Developer Mode"), and fall back to
creating a deep copy in case symlinks are not supported.</para>
</listitem>
</itemizedlist>

<para>Note that this setting has no effect where Cygwin knows that the
Expand Down

0 comments on commit b8e842e

Please sign in to comment.