From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from sa-prd-fep-046.btinternet.com (mailomta17-sa.btinternet.com [213.120.69.23]) by sourceware.org (Postfix) with ESMTPS id 7D47D3861800 for ; Tue, 10 Aug 2021 17:03:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7D47D3861800 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=dronecode.org.uk Authentication-Results: sourceware.org; spf=none smtp.mailfrom=dronecode.org.uk Received: from sa-prd-rgout-002.btmx-prd.synchronoss.net ([10.2.38.5]) by sa-prd-fep-046.btinternet.com with ESMTP id <20210810170354.LXIN28305.sa-prd-fep-046.btinternet.com@sa-prd-rgout-002.btmx-prd.synchronoss.net>; Tue, 10 Aug 2021 18:03:54 +0100 Authentication-Results: btinternet.com; none X-SNCR-Rigid: 60FF56FA02420AE4 X-Originating-IP: [86.140.112.60] X-OWM-Source-IP: 86.140.112.60 (GB) X-OWM-Env-Sender: jonturney@btinternet.com X-VadeSecure-score: verdict=clean score=0/300, class=clean X-RazorGate-Vade: gggruggvucftvghtrhhoucdtuddrgedvtddrjeelgddutdelucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuueftkffvkffujffvgffngfevqffopdfqfgfvnecuuegrihhlohhuthemuceftddunecunecujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeflohhnucfvuhhrnhgvhicuoehjohhnrdhtuhhrnhgvhiesughrohhnvggtohguvgdrohhrghdruhhkqeenucggtffrrghtthgvrhhnpeefieduveehgfffffeuueehleefgeevfedvffeljeefheduteelteelvdettefhvdenucfkphepkeeirddugedtrdduuddvrdeitdenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhephhgvlhhopehlohgtrghlhhhoshhtrdhlohgtrghlughomhgrihhnpdhinhgvthepkeeirddugedtrdduuddvrdeitddpmhgrihhlfhhrohhmpeeojhhonhdrthhurhhnvgihsegurhhonhgvtghouggvrdhorhhgrdhukheqpdhrtghpthhtohepoegthihgfihinhdqrghpphhssegthihgfihinhdrtghomheqpdhrtghpthhtohepoehjohhnrdhtuhhrnhgvhiesughrohhnvggtohguvgdrohhrghdruhhkqe X-RazorGate-Vade-Verdict: clean 0 X-RazorGate-Vade-Classification: clean Received: from localhost.localdomain (86.140.112.60) by sa-prd-rgout-002.btmx-prd.synchronoss.net (5.8.340) (authenticated as jonturney@btinternet.com) id 60FF56FA02420AE4; Tue, 10 Aug 2021 18:03:54 +0100 From: Jon Turney To: cygwin-apps@cygwin.com Cc: Jon Turney Subject: [PATCH setup 01/11] Add support for creating WSL symlinks Date: Tue, 10 Aug 2021 18:02:18 +0100 Message-Id: <20210810170228.1690-2-jon.turney@dronecode.org.uk> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210810170228.1690-1-jon.turney@dronecode.org.uk> References: <20210810170228.1690-1-jon.turney@dronecode.org.uk> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-1200.5 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: cygwin-apps@cygwin.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Cygwin package maintainer discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 10 Aug 2021 17:04:02 -0000 --- inilintmain.cc | 7 +++ mklink2.cc | 143 +++++++++++++++++++++++++++++++++++++++++++++++-- mklink2.h | 10 ++++ 3 files changed, 157 insertions(+), 3 deletions(-) diff --git a/inilintmain.cc b/inilintmain.cc index f31e5eb..886c152 100644 --- a/inilintmain.cc +++ b/inilintmain.cc @@ -56,3 +56,10 @@ main (int argc, char **argv) return 0; } + +const std::string & +get_root_dir () +{ + static std::string empty; + return empty; +} diff --git a/mklink2.cc b/mklink2.cc index 0b73403..3fe5b15 100644 --- a/mklink2.cc +++ b/mklink2.cc @@ -5,6 +5,11 @@ #include "shlobj.h" #include "mklink2.h" #include "filemanip.h" +#include "winioctl.h" +#include "LogSingleton.h" +#include "mount.h" + +SymlinkTypeEnum symlinkType = SymlinkTypeMagic; // default to historical behaviour /* This part of the code must be in C because the C++ interface to COM doesn't work. */ @@ -38,9 +43,8 @@ make_link_2 (char const *exepath, char const *args, char const *icon, char const #define SYMLINK_COOKIE "!" -extern "C" -int -mkcygsymlink (const char *from, const char *to) +static int +mkmagiccygsymlink (const char *from, const char *to) { char buf[strlen (SYMLINK_COOKIE) + 4096]; unsigned long w; @@ -72,6 +76,139 @@ mkcygsymlink (const char *from, const char *to) return 1; } +#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; /* Value is apparently always 2 for symlinks. */ + char PathBuffer[1];/* UTF-8 encoded POSIX path + Isn't \0 terminated. + Length is ReparseDataLength - sizeof (FileType). + */ + } LxSymlinkReparseBuffer; +} REPARSE_LX_SYMLINK_BUFFER,*PREPARSE_LX_SYMLINK_BUFFER; + +static int +mkwslsymlink (const char *from, const char *to) +{ + /* Construct the reparse path */ + std::string lxsymto; + if (to[0] == '/') + { + /* If 'to' is absolute and starts with '/cygdrive' or /proc/cygdrive', + this is a problem because: (i) the cygdrive prefix might be different, + and (ii) the target drive might not exist, on the install system. + + Because of these problems, we don't expect any install packages to have + links like that (they should instead be created by post-install + scripts), but fail if they do. + */ + if ((strncmp(to, "/cygdrive", 9) == 0) || + (strncmp(to, "/proc/cygdrive", 14) == 0)) + { + Log (LOG_PLAIN) << "Refusing to create WSL symlink to" << to << " as it starts with /cygdrive" << endLog; + return 1; + } + + /* Otherwise, we convert the absolute path 'to' into a form a WSL + compatible form, constructed from the '/mnt' prefix and the cygwin root + directory e.g. /mnt/c/cygwin64/ */ + lxsymto = "/mnt/"; + std::string root = get_root_dir(); + if (root[1] == ':') + { + lxsymto.append(1, tolower(root.c_str()[0])); + lxsymto.append("/"); + lxsymto.append(&(root[3])); + } + else + { + // root dir is UNC path ??? + lxsymto.append(root.c_str()); + } + lxsymto.append(to); + } + else + { + /* Otherwise 'to' is relative to 'from', so leave it alone */ + lxsymto = to; + } + + /* Create reparse point. */ + SECURITY_DESCRIPTOR sd; + acl_t acl; + nt_sec.GetPosixPerms (from, NULL, NULL, 0644, sd, acl); + + const size_t flen = strlen (from) + 7; + WCHAR wfrom[flen]; + mklongpath (wfrom, from, flen); + wfrom[1] = '?'; + + HANDLE fh; + UNICODE_STRING ufrom; + IO_STATUS_BLOCK io; + OBJECT_ATTRIBUTES attr; + RtlInitUnicodeString (&ufrom, wfrom); + InitializeObjectAttributes (&attr, &ufrom, OBJ_CASE_INSENSITIVE, NULL, &sd); + NTSTATUS status = NtCreateFile (&fh, + DELETE | FILE_GENERIC_WRITE | READ_CONTROL | WRITE_DAC, + &attr, + &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)) + { + Log (LOG_PLAIN) << "NtCreateFile status " << std::hex << status << endLog; + return 1; + } + + /* Set content of the reparse point */ + size_t tlen = lxsymto.length(); + REPARSE_LX_SYMLINK_BUFFER *rpl = (REPARSE_LX_SYMLINK_BUFFER *) new char[sizeof(REPARSE_LX_SYMLINK_BUFFER) + tlen]; + rpl->ReparseTag = IO_REPARSE_TAG_LX_SYMLINK; + rpl->ReparseDataLength = sizeof (DWORD) + tlen; + rpl->Reserved = 0; + rpl->LxSymlinkReparseBuffer.FileType = 2; + memcpy(rpl->LxSymlinkReparseBuffer.PathBuffer, lxsymto.c_str(), tlen); + + 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)) + { + Log (LOG_PLAIN) << "FSCTL_SET_REPARSE_POINT status " << std::hex << status << endLog; + } + + delete rpl; + NtClose(fh); + return NT_SUCCESS (status) ? 0 : 1; +} + +int +mkcygsymlink (const char *from, const char *to) +{ + if (symlinkType == SymlinkTypeWsl) + { + if (!mkwslsymlink (from, to)) + return 0; + } + + /* fall back to magic symlink, if selected method fails */ + return mkmagiccygsymlink(from, to); +} + static struct { FILE_LINK_INFORMATION fli; WCHAR namebuf[32768]; diff --git a/mklink2.h b/mklink2.h index 0244748..fda17f6 100644 --- a/mklink2.h +++ b/mklink2.h @@ -17,4 +17,14 @@ extern "C" }; #endif +typedef enum +{ + SymlinkTypeMagic, + SymlinkTypeShortcut, + SymlinkTypeNative, + SymlinkTypeWsl, +} SymlinkTypeEnum; + +extern SymlinkTypeEnum symlinkType; + #endif /* SETUP_MKLINK2_H */ -- 2.32.0