public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin] Cygwin: symlinks: create WSL symlinks on supporting filesystems
@ 2020-04-03 19:45 Corinna Vinschen
0 siblings, 0 replies; only message in thread
From: Corinna Vinschen @ 2020-04-03 19:45 UTC (permalink / raw)
To: cygwin-cvs
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=44da5e4b8c89bfcee79eb83fd3b7142720489940
commit 44da5e4b8c89bfcee79eb83fd3b7142720489940
Author: Corinna Vinschen <corinna@vinschen.de>
Date: Fri Apr 3 21:40:01 2020 +0200
Cygwin: symlinks: create WSL symlinks on supporting filesystems
WSL symlinks are reparse points containing a POSIX path in UTF-8.
On filesystems supporting reparse points, use this symlink type.
On other filesystems, or in case of error, fall back to the good
old plain SYSTEM file.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diff:
---
winsup/cygwin/path.cc | 127 +++++++++++++++++++++++++++++++++++---------
winsup/cygwin/release/3.1.5 | 2 +-
winsup/doc/new-features.xml | 2 +-
3 files changed, 105 insertions(+), 26 deletions(-)
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 7d9d61fcd..e6dc03ffa 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1845,6 +1845,97 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
return 0;
}
+#ifndef IO_REPARSE_TAG_LX_SYMLINK
+#define IO_REPARSE_TAG_LX_SYMLINK (0xa000001d)
+#endif
+
+typedef struct _REPARSE_LX_SYMLINK_BUFFER
+{
+ DWORD ReparseTag;
+ WORD ReparseDataLength;
+ WORD Reserved;
+ struct {
+ DWORD FileType; /* Take member name with a grain of salt. Value is
+ apparently always 2 for symlinks. */
+ char PathBuffer[1];/* POSIX path as given to symlink(2).
+ Path is not \0 terminated.
+ Length is ReparseDataLength - sizeof (FileType).
+ Always UTF-8.
+ Chars given in incompatible codesets, e. g. umlauts
+ in ISO-8859-x, are converted to the Unicode
+ REPLACEMENT CHARACTER 0xfffd == \xef\xbf\bd */
+ } LxSymlinkReparseBuffer;
+} REPARSE_LX_SYMLINK_BUFFER,*PREPARSE_LX_SYMLINK_BUFFER;
+
+static int
+symlink_wsl (const char *oldpath, path_conv &win32_newpath)
+{
+ tmp_pathbuf tp;
+ PREPARSE_LX_SYMLINK_BUFFER rpl = (PREPARSE_LX_SYMLINK_BUFFER) tp.c_get ();
+ char *path_buf = rpl->LxSymlinkReparseBuffer.PathBuffer;
+ const int max_pathlen = MAXIMUM_REPARSE_DATA_BUFFER_SIZE
+ - offsetof (REPARSE_LX_SYMLINK_BUFFER,
+ LxSymlinkReparseBuffer.PathBuffer);
+ PWCHAR utf16 = tp.w_get ();
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ OBJECT_ATTRIBUTES attr;
+ HANDLE fh;
+ int len;
+
+ rpl->ReparseTag = IO_REPARSE_TAG_LX_SYMLINK;
+ rpl->Reserved = 0;
+ rpl->LxSymlinkReparseBuffer.FileType = 2;
+ /* Convert cygdrive prefix to "/mnt" for WSL compatibility. */
+ if (path_prefix_p (mount_table->cygdrive, oldpath,
+ mount_table->cygdrive_len, false))
+ stpcpy (stpcpy (path_buf, "/mnt"),
+ oldpath + mount_table->cygdrive_len - 1);
+ else
+ *stpncpy (path_buf, oldpath, max_pathlen) = '\0';
+ /* Convert target path to UTF-16 and then back to UTF-8 to make sure the
+ WSL symlink is in UTF-8, independet of the current Cygwin codeset. */
+ sys_mbstowcs (utf16, NT_MAX_PATH, path_buf);
+ len = WideCharToMultiByte (CP_UTF8, 0, utf16, -1, path_buf, max_pathlen,
+ NULL, NULL);
+ /* Length is omitting trailing \0. */
+ rpl->ReparseDataLength = sizeof (DWORD) + len - 1;
+ /* Create reparse point. */
+ status = NtCreateFile (&fh, DELETE | FILE_GENERIC_WRITE
+ | READ_CONTROL | WRITE_DAC,
+ win32_newpath.get_object_attr (attr, sec_none_nih),
+ &io, NULL, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_VALID_FLAGS, FILE_CREATE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_NON_DIRECTORY_FILE
+ | FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_OPEN_REPARSE_POINT,
+ NULL, 0);
+ if (!NT_SUCCESS (status))
+ {
+ SetLastError (RtlNtStatusToDosError (status));
+ return -1;
+ }
+ set_created_file_access (fh, win32_newpath, S_IFLNK | STD_RBITS | STD_WBITS);
+ status = NtFsControlFile (fh, NULL, NULL, NULL, &io, FSCTL_SET_REPARSE_POINT,
+ (LPVOID) rpl, REPARSE_DATA_BUFFER_HEADER_SIZE
+ + rpl->ReparseDataLength,
+ NULL, 0);
+ if (!NT_SUCCESS (status))
+ {
+ SetLastError (RtlNtStatusToDosError (status));
+ FILE_DISPOSITION_INFORMATION fdi = { TRUE };
+ status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
+ FileDispositionInformation);
+ NtClose (fh);
+ if (!NT_SUCCESS (status))
+ debug_printf ("Setting delete dispostion failed, status = %y", status);
+ return -1;
+ }
+ NtClose (fh);
+ return 0;
+}
+
int
symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
{
@@ -1908,7 +1999,7 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
__leave;
}
- /* Handle NFS and native symlinks in their own functions. */
+ /* Handle NFS, native symlinks and WSL symlinks in their own functions. */
switch (wsym_type)
{
case WSYM_nfs:
@@ -1928,6 +2019,17 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice)
}
/* Otherwise, fall back to default symlink type. */
wsym_type = WSYM_sysfile;
+ /*FALLTHRU*/
+ case WSYM_sysfile:
+ if (win32_newpath.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS)
+ {
+ res = symlink_wsl (oldpath, win32_newpath);
+ if (!res)
+ __leave;
+ }
+ /* On FSes not supporting reparse points, or in case of an error
+ creating the WSL symlink, fall back to creating the plain old
+ SYSTEM file symlink. */
break;
default:
break;
@@ -2360,29 +2462,6 @@ check_reparse_point_string (PUNICODE_STRING subst)
return false;
}
-#ifndef IO_REPARSE_TAG_LX_SYMLINK
-#define IO_REPARSE_TAG_LX_SYMLINK (0xa000001d)
-#endif
-
-typedef struct _REPARSE_LX_SYMLINK_BUFFER
-{
- DWORD ReparseTag;
- WORD ReparseDataLength;
- WORD Reserved;
- struct {
- DWORD FileType; /* Take member name with a grain of salt. Value is
- apparently always 2 for symlinks. */
- char PathBuffer[1];/* POSIX path as given to symlink(2).
- Path is not \0 terminated.
- Length is ReparseDataLength - sizeof (FileType).
- Always UTF-8.
- Chars given in incompatible codesets, e. g. umlauts
- in ISO-8859-x, are converted to the Unicode
- REPLACEMENT CHARACTER 0xfffd == \xef\xbf\bd */
- } LxSymlinkReparseBuffer;
-} REPARSE_LX_SYMLINK_BUFFER,*PREPARSE_LX_SYMLINK_BUFFER;
-
-
/* Return values:
<0: Negative errno.
0: No symlink.
diff --git a/winsup/cygwin/release/3.1.5 b/winsup/cygwin/release/3.1.5
index 6f16aad93..c1d1cd89d 100644
--- a/winsup/cygwin/release/3.1.5
+++ b/winsup/cygwin/release/3.1.5
@@ -1,7 +1,7 @@
What changed:
-------------
-- Support WSL symlinks.
+- Support WSL symlinks. Create those by default now.
Bug Fixes:
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index a200300f2..60ae60de4 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -83,7 +83,7 @@ https://gitlab.freedesktop.org/terminal-wg/specifications/issues/9.
</para></listitem>
<listitem><para>
-Support WSL symlinks.
+Support WSL symlinks. Create those by default now.
</para></listitem>
</itemizedlist>
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2020-04-03 19:45 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-03 19:45 [newlib-cygwin] Cygwin: symlinks: create WSL symlinks on supporting filesystems Corinna Vinschen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).