This patch synchronizes msys2/MSYS2-packages/msys2-runtime with msys2/msys2-runtime after merging https://github.com/msys2/msys2-runtime/pull/16. We specifically override Cygwin's symlink() behavior to make deep copies instead of creating a special-crafted system file that Cygwin (MSYS2, and only those two) will recognize as symbolic link. The patch to override this behavior is incomplete, though: it hacks up the WSYM_sysfile code path, which causes all kinds of problems: - Contrary to the documentation, MSYS=winsymlinks:native won't fall back to creating Cygwin-style symbolic links. Instead, it (quite surprisingly) creates deep copies instead. - There is no way to opt into the original Cygwin behavior because that code path is now dead code. - The fact that the WSYM_sysfile code path is modified to do something very different from what it is intended to do means that all changes that Cygwin makes to that code path have to be inspected, and occasionally even more hacks have to be put on top, such as 44bb133, where we specifically had to disable Cygwin's code to try creating WSL symlinks before falling back to creating system files instead). Let's fix this by introducing a proper new mode: MSYS=winsymlinks:deepcopy. This mode is made the default so that users should be unaffected by this PR. Users wishing to let the MSYS2 runtime create Cygwin-style symbolic links can ask for that by setting MSYS=winsymlinks:sysfile. By fixing this issue, we can now stop disabling Cygwin's WSL symlink behavior, too: it is in the sysfile code path and won't affect the default behavior of the MSYS2 runtime. While at it, the indentation of the original patch is fixed, too. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1107 lines
41 KiB
Diff
1107 lines
41 KiB
Diff
From 0e31ff61a74d2d8fefae215753425e27c2a499df Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?=
|
|
=?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= <alexey.pawlow@gmail.com>
|
|
Date: Sun, 14 Apr 2019 21:17:46 +0300
|
|
Subject: [PATCH 03/N] Add functionality for converting UNIX paths in
|
|
arguments and environment variables to Windows form for native Win32
|
|
applications.
|
|
|
|
---
|
|
winsup/cygwin/Makefile.in | 1 +
|
|
winsup/cygwin/environ.cc | 24 +-
|
|
winsup/cygwin/environ.h | 2 +-
|
|
winsup/cygwin/external.cc | 2 +-
|
|
winsup/cygwin/include/sys/cygwin.h | 6 +
|
|
winsup/cygwin/msys2_path_conv.cc | 641 +++++++++++++++++++++++++++++
|
|
winsup/cygwin/msys2_path_conv.h | 147 +++++++
|
|
winsup/cygwin/path.cc | 69 ++++
|
|
winsup/cygwin/spawn.cc | 48 ++-
|
|
winsup/cygwin/winf.h | 4 +
|
|
10 files changed, 935 insertions(+), 9 deletions(-)
|
|
create mode 100644 winsup/cygwin/msys2_path_conv.cc
|
|
create mode 100644 winsup/cygwin/msys2_path_conv.h
|
|
|
|
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
|
|
index 92890d8..f9bb33c 100644
|
|
--- a/winsup/cygwin/Makefile.in
|
|
+++ b/winsup/cygwin/Makefile.in
|
|
@@ -346,6 +346,7 @@ DLL_OFILES:= \
|
|
mmap_alloc.o \
|
|
msg.o \
|
|
msgcat.o \
|
|
+ msys2_path_conv.o \
|
|
mount.o \
|
|
net.o \
|
|
netdb.o \
|
|
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
|
|
index 3a03657..73df083 100644
|
|
--- a/winsup/cygwin/environ.cc
|
|
+++ b/winsup/cygwin/environ.cc
|
|
@@ -1056,7 +1056,7 @@ env_compare (const void *key, const void *memb)
|
|
to the child. */
|
|
char ** __reg3
|
|
build_env (const char * const *envp, PWCHAR &envblock, int &envc,
|
|
- bool no_envblock, HANDLE new_token)
|
|
+ bool no_envblock, HANDLE new_token, bool keep_posix)
|
|
{
|
|
PWCHAR cwinenv = NULL;
|
|
size_t winnum = 0;
|
|
@@ -1149,6 +1149,19 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc,
|
|
for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++)
|
|
{
|
|
bool calc_tl = !no_envblock;
|
|
+#ifdef __MSYS__
|
|
+ /* Don't pass timezone environment to non-msys applications */
|
|
+ if (!keep_posix && ascii_strncasematch(*srcp, "TZ=", 3))
|
|
+ {
|
|
+ const char *v = *srcp + 3;
|
|
+ if (*v == ':')
|
|
+ goto next1;
|
|
+ for (; *v; v++)
|
|
+ if (!isalpha(*v) && !isdigit(*v) &&
|
|
+ *v != '-' && *v != '+' && *v != ':')
|
|
+ goto next1;
|
|
+ }
|
|
+#endif
|
|
/* Look for entries that require special attention */
|
|
for (unsigned i = 0; i < SPENVS_SIZE; i++)
|
|
if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp)))
|
|
@@ -1269,6 +1282,15 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc,
|
|
saw_PATH = true;
|
|
}
|
|
}
|
|
+#ifdef __MSYS__
|
|
+ else if (!keep_posix) {
|
|
+ char *win_arg = arg_heuristic(*srcp);
|
|
+ debug_printf("WIN32_PATH is %s", win_arg);
|
|
+ p = cstrdup1(win_arg);
|
|
+ if (win_arg != *srcp)
|
|
+ free (win_arg);
|
|
+ }
|
|
+#endif
|
|
else
|
|
p = *srcp; /* Don't worry about it */
|
|
|
|
diff --git a/winsup/cygwin/environ.h b/winsup/cygwin/environ.h
|
|
index 269591a..71c3f22 100644
|
|
--- a/winsup/cygwin/environ.h
|
|
+++ b/winsup/cygwin/environ.h
|
|
@@ -43,7 +43,7 @@ extern "C" char **__cygwin_environ, ***main_environ;
|
|
extern "C" char __stdcall **cur_environ ();
|
|
#endif
|
|
char ** __reg3 build_env (const char * const *envp, PWCHAR &envblock,
|
|
- int &envc, bool need_envblock, HANDLE new_token);
|
|
+ int &envc, bool need_envblock, HANDLE new_token, bool keep_posix);
|
|
|
|
char ** __reg2 win32env_to_cygenv (PWCHAR rawenv, bool posify);
|
|
|
|
diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc
|
|
index 74413a8..6adf620 100644
|
|
--- a/winsup/cygwin/external.cc
|
|
+++ b/winsup/cygwin/external.cc
|
|
@@ -141,7 +141,7 @@ create_winenv (const char * const *env)
|
|
int unused_envc;
|
|
PWCHAR envblock = NULL;
|
|
char **envp = build_env (env ?: cur_environ (), envblock, unused_envc, false,
|
|
- NULL);
|
|
+ NULL, true);
|
|
PWCHAR p = envblock;
|
|
|
|
if (envp)
|
|
diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h
|
|
index 805671e..b395e96 100644
|
|
--- a/winsup/cygwin/include/sys/cygwin.h
|
|
+++ b/winsup/cygwin/include/sys/cygwin.h
|
|
@@ -83,6 +83,12 @@ extern ssize_t cygwin_conv_path_list (cygwin_conv_path_t what, const void *from,
|
|
to one of the above values, or to ENOMEM if malloc fails. */
|
|
extern void *cygwin_create_path (cygwin_conv_path_t what, const void *from);
|
|
|
|
+extern char * arg_heuristic_with_exclusions (char const * const arg,
|
|
+ char const * exclusions,
|
|
+ size_t exclusions_count);
|
|
+
|
|
+extern char * arg_heuristic (char const * const);
|
|
+
|
|
extern pid_t cygwin_winpid_to_pid (int);
|
|
extern int cygwin_posix_path_list_p (const char *);
|
|
extern void cygwin_split_path (const char *, char *, char *);
|
|
diff --git a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc
|
|
new file mode 100644
|
|
index 0000000..f9dcda5
|
|
--- /dev/null
|
|
+++ b/winsup/cygwin/msys2_path_conv.cc
|
|
@@ -0,0 +1,641 @@
|
|
+/*
|
|
+ The MSYS2 Path conversion source code is licensed under:
|
|
+
|
|
+ CC0 1.0 Universal
|
|
+
|
|
+ Official translations of this legal tool are available
|
|
+
|
|
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
|
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
|
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
|
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
|
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
|
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
|
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
|
+ HEREUNDER.
|
|
+
|
|
+ Statement of Purpose
|
|
+
|
|
+ The laws of most jurisdictions throughout the world automatically
|
|
+ confer exclusive Copyright and Related Rights (defined below) upon the
|
|
+ creator and subsequent owner(s) (each and all, an "owner") of an
|
|
+ original work of authorship and/or a database (each, a "Work").
|
|
+
|
|
+ Certain owners wish to permanently relinquish those rights to a Work
|
|
+ for the purpose of contributing to a commons of creative, cultural and
|
|
+ scientific works ("Commons") that the public can reliably and without
|
|
+ fear of later claims of infringement build upon, modify, incorporate
|
|
+ in other works, reuse and redistribute as freely as possible in any
|
|
+ form whatsoever and for any purposes, including without limitation
|
|
+ commercial purposes. These owners may contribute to the Commons to
|
|
+ promote the ideal of a free culture and the further production of
|
|
+ creative, cultural and scientific works, or to gain reputation or
|
|
+ greater distribution for their Work in part through the use and
|
|
+ efforts of others.
|
|
+
|
|
+ For these and/or other purposes and motivations, and without any
|
|
+ expectation of additional consideration or compensation, the person
|
|
+ associating CC0 with a Work (the "Affirmer"), to the extent that he or
|
|
+ she is an owner of Copyright and Related Rights in the Work,
|
|
+ voluntarily elects to apply CC0 to the Work and publicly distribute
|
|
+ the Work under its terms, with knowledge of his or her Copyright and
|
|
+ Related Rights in the Work and the meaning and intended legal effect
|
|
+ of CC0 on those rights.
|
|
+
|
|
+ 1. Copyright and Related Rights. A Work made available under CC0 may
|
|
+ be protected by copyright and related or neighboring rights
|
|
+ ("Copyright and Related Rights"). Copyright and Related Rights
|
|
+ include, but are not limited to, the following:
|
|
+
|
|
+ the right to reproduce, adapt, distribute, perform, display,
|
|
+ communicate, and translate a Work;
|
|
+ moral rights retained by the original author(s) and/or performer(s);
|
|
+ publicity and privacy rights pertaining to a person's image or
|
|
+ likeness depicted in a Work;
|
|
+ rights protecting against unfair competition in regards to a Work,
|
|
+ subject to the limitations in paragraph 4(a), below;
|
|
+ rights protecting the extraction, dissemination, use and reuse of data
|
|
+ in a Work;
|
|
+ database rights (such as those arising under Directive 96/9/EC of the
|
|
+ European Parliament and of the Council of 11 March 1996 on the legal
|
|
+ protection of databases, and under any national implementation
|
|
+ thereof, including any amended or successor version of such
|
|
+ directive); and
|
|
+ other similar, equivalent or corresponding rights throughout the world
|
|
+ based on applicable law or treaty, and any national implementations
|
|
+ thereof.
|
|
+
|
|
+ 2. Waiver. To the greatest extent permitted by, but not in
|
|
+ contravention of, applicable law, Affirmer hereby overtly, fully,
|
|
+ permanently, irrevocably and unconditionally waives, abandons, and
|
|
+ surrenders all of Affirmer's Copyright and Related Rights and
|
|
+ associated claims and causes of action, whether now known or unknown
|
|
+ (including existing as well as future claims and causes of action), in
|
|
+ the Work (i) in all territories worldwide, (ii) for the maximum
|
|
+ duration provided by applicable law or treaty (including future time
|
|
+ extensions), (iii) in any current or future medium and for any number
|
|
+ of copies, and (iv) for any purpose whatsoever, including without
|
|
+ limitation commercial, advertising or promotional purposes (the
|
|
+ "Waiver"). Affirmer makes the Waiver for the benefit of each member of
|
|
+ the public at large and to the detriment of Affirmer's heirs and
|
|
+ successors, fully intending that such Waiver shall not be subject to
|
|
+ revocation, rescission, cancellation, termination, or any other legal
|
|
+ or equitable action to disrupt the quiet enjoyment of the Work by the
|
|
+ public as contemplated by Affirmer's express Statement of Purpose.
|
|
+
|
|
+ 3. Public License Fallback. Should any part of the Waiver for any
|
|
+ reason be judged legally invalid or ineffective under applicable law,
|
|
+ then the Waiver shall be preserved to the maximum extent permitted
|
|
+ taking into account Affirmer's express Statement of Purpose. In
|
|
+ addition, to the extent the Waiver is so judged Affirmer hereby grants
|
|
+ to each affected person a royalty-free, non transferable, non
|
|
+ sublicensable, non exclusive, irrevocable and unconditional license to
|
|
+ exercise Affirmer's Copyright and Related Rights in the Work (i) in
|
|
+ all territories worldwide, (ii) for the maximum duration provided by
|
|
+ applicable law or treaty (including future time extensions), (iii) in
|
|
+ any current or future medium and for any number of copies, and (iv)
|
|
+ for any purpose whatsoever, including without limitation commercial,
|
|
+ advertising or promotional purposes (the "License"). The License shall
|
|
+ be deemed effective as of the date CC0 was applied by Affirmer to the
|
|
+ Work. Should any part of the License for any reason be judged legally
|
|
+ invalid or ineffective under applicable law, such partial invalidity
|
|
+ or ineffectiveness shall not invalidate the remainder of the License,
|
|
+ and in such case Affirmer hereby affirms that he or she will not (i)
|
|
+ exercise any of his or her remaining Copyright and Related Rights in
|
|
+ the Work or (ii) assert any associated claims and causes of action
|
|
+ with respect to the Work, in either case contrary to Affirmer's
|
|
+ express Statement of Purpose.
|
|
+
|
|
+ 4. Limitations and Disclaimers.
|
|
+
|
|
+ No trademark or patent rights held by Affirmer are waived, abandoned,
|
|
+ surrendered, licensed or otherwise affected by this document.
|
|
+ Affirmer offers the Work as-is and makes no representations or
|
|
+ warranties of any kind concerning the Work, express, implied,
|
|
+ statutory or otherwise, including without limitation warranties of
|
|
+ title, merchantability, fitness for a particular purpose, non
|
|
+ infringement, or the absence of latent or other defects, accuracy, or
|
|
+ the present or absence of errors, whether or not discoverable, all to
|
|
+ the greatest extent permissible under applicable law.
|
|
+ Affirmer disclaims responsibility for clearing rights of other persons
|
|
+ that may apply to the Work or any use thereof, including without
|
|
+ limitation any person's Copyright and Related Rights in the Work.
|
|
+ Further, Affirmer disclaims responsibility for obtaining any necessary
|
|
+ consents, permissions or other rights required for any use of the
|
|
+ Work.
|
|
+ Affirmer understands and acknowledges that Creative Commons is not a
|
|
+ party to this document and has no duty or obligation with respect to
|
|
+ this CC0 or use of the Work.
|
|
+
|
|
+ Contributions thanks to:
|
|
+ niXman <i.nixman@autistici.org>
|
|
+ Ely Arzhannikov <iarzhannikov@gmail.com>
|
|
+ Alexey Pavlov <alexpux@gmail.com>
|
|
+ Ray Donnelly <mingw.android@gmail.com>
|
|
+ Johannes Schindelin <johannes.schindelin@gmx.de>
|
|
+
|
|
+*/
|
|
+
|
|
+#include "winsup.h"
|
|
+#include "miscfuncs.h"
|
|
+#include <ctype.h>
|
|
+#include <winioctl.h>
|
|
+#include <shlobj.h>
|
|
+#include <sys/param.h>
|
|
+#include <sys/cygwin.h>
|
|
+#include "cygerrno.h"
|
|
+#include "security.h"
|
|
+#include "path.h"
|
|
+#include "fhandler.h"
|
|
+#include "dtable.h"
|
|
+#include "cygheap.h"
|
|
+#include "shared_info.h"
|
|
+#include "cygtls.h"
|
|
+#include "tls_pbuf.h"
|
|
+#include "environ.h"
|
|
+#include <assert.h>
|
|
+#include <ntdll.h>
|
|
+#include <wchar.h>
|
|
+#include <wctype.h>
|
|
+
|
|
+#include "msys2_path_conv.h"
|
|
+
|
|
+typedef enum PATH_TYPE_E {
|
|
+ NONE = 0,
|
|
+ SIMPLE_WINDOWS_PATH,
|
|
+ ESCAPE_WINDOWS_PATH,
|
|
+ WINDOWS_PATH_LIST,
|
|
+ UNC,
|
|
+ ESCAPED_PATH,
|
|
+ ROOTED_PATH,
|
|
+ POSIX_PATH_LIST,
|
|
+ RELATIVE_PATH,
|
|
+ URL
|
|
+} path_type;
|
|
+
|
|
+int is_special_posix_path(const char* from, const char* to, char** dst, const char* dstend);
|
|
+void posix_to_win32_path(const char* from, const char* to, char** dst, const char* dstend);
|
|
+
|
|
+
|
|
+path_type find_path_start_and_type(const char** src, int recurse, const char* end);
|
|
+void copy_to_dst(const char* from, const char* to, char** dst, const char* dstend);
|
|
+void convert_path(const char** from, const char* to, path_type type, char** dst, const char* dstend);
|
|
+
|
|
+//Transformations
|
|
+//SIMPLE_WINDOWS_PATH converter. Copy as is. Hold C:\Something\like\this
|
|
+void swp_convert(const char** from, const char* to, char** dst, const char* dstend);
|
|
+//ESCAPE_WINDOWS_PATH converter. Turn backslashes to slashes and skip first /. Hold /C:\Somethind\like\this
|
|
+void ewp_convert(const char** from, const char* to, char** dst, const char* dstend);
|
|
+//WINDOWS_PATH_LIST converter. Copy as is. Hold /something/like/this;
|
|
+void wpl_convert(const char** from, const char* to, char** dst, const char* dstend);
|
|
+//UNC convert converter. Copy as is. Hold //somethig/like/this
|
|
+void unc_convert(const char** from, const char* to, char** dst, const char* dstend);
|
|
+//ESCAPED_PATH converter. Turn backslashes to slashes and skip first /. Hold //something\like\this
|
|
+void ep_convert(const char** from, const char* to, char** dst, const char* dstend);
|
|
+//ROOTED_PATH converter. Prepend root dir to front. Hold /something/like/this
|
|
+void rp_convert(const char** from, const char* to, char** dst, const char* dstend);
|
|
+//URL converter. Copy as is.
|
|
+void url_convert(const char** from, const char* to, char** dst, const char* dstend);
|
|
+//POSIX_PATH_LIST. Hold x::x/y:z
|
|
+void ppl_convert(const char** from, const char* to, char** dst, const char* dstend);
|
|
+
|
|
+
|
|
+void find_end_of_posix_list(const char** to, int* in_string) {
|
|
+ for (; **to != '\0' && (in_string ? (**to != *in_string) : **to != ' '); ++*to) {
|
|
+ }
|
|
+
|
|
+ if (**to == *in_string) {
|
|
+ *in_string = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+void find_end_of_rooted_path(const char** from, const char** to, int* in_string) {
|
|
+ for (const char* it = *from; *it != '\0' && it != *to; ++it)
|
|
+ if (*it == '.' && *(it + 1) == '.' && *(it - 1) == '/') {
|
|
+ *to = it - 1;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (; **to != '\0'; ++*to) {
|
|
+ if (*in_string == 0 && **to == ' ') {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (**to == *in_string) {
|
|
+ *in_string = 0;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (**to == '/') {
|
|
+ if (*(*to - 1) == ' ') {
|
|
+ *to -= 1;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void sub_convert(const char** from, const char** to, char** dst, const char* dstend, int* in_string) {
|
|
+ const char* copy_from = *from;
|
|
+ path_type type = find_path_start_and_type(from, false, *to);
|
|
+
|
|
+ if (type == POSIX_PATH_LIST) {
|
|
+ find_end_of_posix_list(to, in_string);
|
|
+ }
|
|
+
|
|
+ if (type == ROOTED_PATH) {
|
|
+ find_end_of_rooted_path(from, to, in_string);
|
|
+ }
|
|
+
|
|
+ copy_to_dst(copy_from, *from, dst, dstend);
|
|
+
|
|
+ if (type != NONE) {
|
|
+ convert_path(from, *to, type, dst, dstend);
|
|
+ }
|
|
+
|
|
+ if (*dst != dstend) {
|
|
+ **dst = **to;
|
|
+ *dst += 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+const char* convert(char *dst, size_t dstlen, const char *src) {
|
|
+ if (dst == NULL || dstlen == 0 || src == NULL) {
|
|
+ return dst;
|
|
+ }
|
|
+
|
|
+ int need_convert = false;
|
|
+ for (const char* it = src; *it != '\0'; ++it) {
|
|
+ if (*it == '\\' || *it == '/') {
|
|
+ need_convert = true;
|
|
+ break;
|
|
+ }
|
|
+ if (isspace(*it)) {
|
|
+ need_convert = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ char* dstit = dst;
|
|
+ char* dstend = dst + dstlen;
|
|
+ if (!need_convert) {
|
|
+ copy_to_dst(src, NULL, &dstit, dstend);
|
|
+ *dstit = '\0';
|
|
+ return dst;
|
|
+ }
|
|
+ *dstend = '\0';
|
|
+
|
|
+ const char* srcit = src;
|
|
+ const char* srcbeg = src;
|
|
+
|
|
+ int in_string = false;
|
|
+
|
|
+ for (; *srcit != '\0'; ++srcit) {
|
|
+ if (*srcit == '\'' || *srcit == '"') {
|
|
+ if (in_string == *srcit) {
|
|
+ if (*(srcit + 1) != in_string) {
|
|
+ in_string = 0;
|
|
+ }
|
|
+ } else {
|
|
+ in_string = *srcit;
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (isspace(*srcit)) {
|
|
+ //sub_convert(&srcbeg, &srcit, &dstit, dstend, &in_string);
|
|
+ //srcbeg = srcit + 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ sub_convert(&srcbeg, &srcit, &dstit, dstend, &in_string);
|
|
+ if (!*srcit) {
|
|
+ *dstit = '\0';
|
|
+ return dst;
|
|
+ }
|
|
+ srcbeg = srcit + 1;
|
|
+ for (; *srcit != '\0'; ++srcit) {
|
|
+ continue;
|
|
+ }
|
|
+ copy_to_dst(srcbeg, srcit, &dstit, dstend);
|
|
+ *dstit = '\0';
|
|
+
|
|
+ /*if (dstit - dst < 2) {
|
|
+ dstit = dst;
|
|
+ copy_to_dst(src, NULL, &dstit, dstend);
|
|
+ *dstit = '\0';
|
|
+ }*/
|
|
+
|
|
+ return dst;
|
|
+}
|
|
+
|
|
+void copy_to_dst(const char* from, const char* to, char** dst, const char* dstend) {
|
|
+ for (; (*from != '\0') && (from != to) && (*dst != dstend); ++from, ++(*dst)) {
|
|
+ **dst = *from;
|
|
+ }
|
|
+}
|
|
+
|
|
+const char** move(const char** p, int count) {
|
|
+ *p += count;
|
|
+ return p;
|
|
+}
|
|
+
|
|
+path_type find_path_start_and_type(const char** src, int recurse, const char* end) {
|
|
+ const char* it = *src;
|
|
+
|
|
+ if (*it == '\0' || it == end) return NONE;
|
|
+
|
|
+ if (!isalnum(*it) && *it != '/' && *it != '\\' && *it != ':' && *it != '-' && *it != '.') {
|
|
+ return find_path_start_and_type(move(src, 1), true, end);
|
|
+ }
|
|
+
|
|
+ path_type result = NONE;
|
|
+
|
|
+ if (isalpha(*it) && *(it + 1) == ':') {
|
|
+ if (*(it + 2) == '\\') {
|
|
+ return SIMPLE_WINDOWS_PATH;
|
|
+ }
|
|
+
|
|
+ if (*(it + 2) == '/' && memchr(it + 2, ':', end - (it + 2)) == NULL) {
|
|
+ return SIMPLE_WINDOWS_PATH;
|
|
+ }
|
|
+
|
|
+ if (*(it + 2) == '/' && memchr(it + 2, ';', end - (it + 2))) {
|
|
+ return WINDOWS_PATH_LIST;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (*it == '.' && (*(it + 1) == '.' || *(it + 1) == '/') && memchr(it + 2, ':', end - (it + 2)) == NULL) {
|
|
+ return RELATIVE_PATH;
|
|
+ }
|
|
+
|
|
+ if (*it == '/') {
|
|
+ it += 1;
|
|
+
|
|
+ if (isalpha(*it) && *(it + 1) == ':') {
|
|
+ return ESCAPE_WINDOWS_PATH;
|
|
+ }
|
|
+
|
|
+ if (*it == '.' && *(it + 1) == '.') {
|
|
+ return SIMPLE_WINDOWS_PATH;
|
|
+ }
|
|
+
|
|
+ if (*it == '/') {
|
|
+ it += 1;
|
|
+ switch(*it) {
|
|
+ case ':': return URL;
|
|
+ case '/': return ESCAPED_PATH;
|
|
+ }
|
|
+ if (memchr(it, '/', end - it))
|
|
+ return UNC;
|
|
+ else
|
|
+ return ESCAPED_PATH;
|
|
+ }
|
|
+
|
|
+ for (; *it != '\0' && it != end; ++it) {
|
|
+ switch(*it) {
|
|
+ case ':': {char ch = *(it + 1); if (ch == '/' || ch == ':' || ch == '.') return POSIX_PATH_LIST;} return WINDOWS_PATH_LIST;
|
|
+ case ';': return WINDOWS_PATH_LIST;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (result != NONE) {
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ return ROOTED_PATH;
|
|
+ }
|
|
+
|
|
+ int starts_with_minus = 0;
|
|
+ int starts_with_minus_alpha = 0;
|
|
+ if (*it == '-') {
|
|
+ starts_with_minus = 1;
|
|
+ it += 1;
|
|
+ if (isalpha(*it)) {
|
|
+ it += 1;
|
|
+ starts_with_minus_alpha = 1;
|
|
+ if (memchr(it, ';', end - it)) {
|
|
+ return WINDOWS_PATH_LIST;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (const char* it2 = it; *it2 != '\0' && it2 != end; ++it2) {
|
|
+ char ch = *it2;
|
|
+ if (starts_with_minus_alpha) {
|
|
+ if (isalpha(ch) && (*(it2+1) == ':') && (*(it2+2) == '/')) {
|
|
+ return SIMPLE_WINDOWS_PATH;
|
|
+ }
|
|
+ if (ch == '/'&& memchr(it2, ',', end - it) == NULL) {
|
|
+ *src = it2;
|
|
+ return find_path_start_and_type(src, true, end);
|
|
+ }
|
|
+ starts_with_minus_alpha = 0;
|
|
+ }
|
|
+ if (ch == '\'' || ch == '"')
|
|
+ starts_with_minus = false;
|
|
+ if ((ch == '=') || (ch == ':' && starts_with_minus) || ((ch == '\'' || ch == '"') && result == NONE)) {
|
|
+ *src = it2 + 1;
|
|
+ return find_path_start_and_type(src, true, end);
|
|
+ }
|
|
+
|
|
+ if (ch == ',' && starts_with_minus) {
|
|
+ *src = it2 + 1;
|
|
+ return find_path_start_and_type(src, true, end);
|
|
+ }
|
|
+
|
|
+ if (ch == ':' && it2 + 1 != end) {
|
|
+ it2 += 1;
|
|
+ ch = *it2;
|
|
+ if (ch == '/' || ch == ':' || ch == '.') {
|
|
+ if (ch == '/' && *(it2 + 1) == '/') {
|
|
+ return URL;
|
|
+ } else {
|
|
+ return POSIX_PATH_LIST;
|
|
+ }
|
|
+ } else if (memchr(it2, '=', end - it) == NULL) {
|
|
+ return SIMPLE_WINDOWS_PATH;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (result != NONE) {
|
|
+ *src = it;
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ return SIMPLE_WINDOWS_PATH;
|
|
+}
|
|
+
|
|
+void convert_path(const char** from, const char* to, path_type type, char** dst, const char* dstend) {
|
|
+ switch(type) {
|
|
+ case SIMPLE_WINDOWS_PATH: swp_convert(from, to, dst, dstend); break;
|
|
+ case ESCAPE_WINDOWS_PATH: ewp_convert(from, to, dst, dstend); break;
|
|
+ case WINDOWS_PATH_LIST: wpl_convert(from, to, dst, dstend); break;
|
|
+ case RELATIVE_PATH: swp_convert(from, to, dst, dstend); break;
|
|
+ case UNC: unc_convert(from, to, dst, dstend); break;
|
|
+ case ESCAPED_PATH: ep_convert(from, to, dst, dstend); break;
|
|
+ case ROOTED_PATH: rp_convert(from, to, dst, dstend); break;
|
|
+ case URL: url_convert(from, to, dst, dstend); break;
|
|
+ case POSIX_PATH_LIST: ppl_convert(from, to, dst, dstend); break;
|
|
+ case NONE: // prevent warnings;
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+void swp_convert(const char** from, const char* to, char** dst, const char* dstend) {
|
|
+ copy_to_dst(*from, to, dst, dstend);
|
|
+}
|
|
+
|
|
+void ewp_convert(const char** from, const char* to, char** dst, const char* dstend) {
|
|
+ *from += 1;
|
|
+ unc_convert(from, to, dst, dstend);
|
|
+}
|
|
+
|
|
+void wpl_convert(const char** from, const char* to, char** dst, const char* dstend) {
|
|
+ swp_convert(from, to, dst, dstend);
|
|
+}
|
|
+
|
|
+void unc_convert(const char** from, const char* to, char** dst, const char* dstend) {
|
|
+ const char* it = *from;
|
|
+ for (; (*it != '\0' && it != to) && (*dst != dstend); ++it, ++(*dst)) {
|
|
+ if (*it == '\\') {
|
|
+ **dst = '/';
|
|
+ } else {
|
|
+ **dst = *it;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void ep_convert(const char** from, const char* to, char** dst, const char* dstend) {
|
|
+ ewp_convert(from, to, dst, dstend);
|
|
+}
|
|
+
|
|
+void rp_convert(const char** from, const char* to, char** dst, const char* dstend) {
|
|
+ const char* it = *from;
|
|
+ const char* real_to = to;
|
|
+
|
|
+ if (*real_to == '\0') {
|
|
+ real_to -= 1;
|
|
+ if (*real_to != '\'' && *real_to != '"') {
|
|
+ real_to += 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!is_special_posix_path(*from, real_to, dst, dstend)) {
|
|
+ posix_to_win32_path(it, real_to, dst, dstend);
|
|
+ }
|
|
+
|
|
+ if (*dst != dstend && real_to != to) {
|
|
+ **dst = *real_to;
|
|
+ *dst += 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+void url_convert(const char** from, const char* to, char** dst, const char* dstend) {
|
|
+ unc_convert(from, to, dst, dstend);
|
|
+}
|
|
+
|
|
+void subp_convert(const char** from, const char* end, int is_url, char** dst, const char* dstend) {
|
|
+ const char* begin = *from;
|
|
+ path_type type = is_url ? URL : find_path_start_and_type(from, 0, end);
|
|
+ copy_to_dst(begin, *from, dst, dstend);
|
|
+
|
|
+ if (type == NONE) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ char* start = *dst;
|
|
+ convert_path(from, end, type, dst, dstend);
|
|
+
|
|
+ if (!is_url) {
|
|
+ for (; start != *dst; ++start) {
|
|
+ if (*start == '/') {
|
|
+ *start = '\\';
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void ppl_convert(const char** from, const char* to, char** dst, const char* dstend) {
|
|
+ const char *orig_dst = *dst;
|
|
+ const char* it = *from;
|
|
+ const char* beg = it;
|
|
+ int prev_was_simc = 0;
|
|
+ int is_url = 0;
|
|
+ for (; (*it != '\0' && it != to) && (*dst != dstend); ++it) {
|
|
+ if (*it == ':') {
|
|
+ if (prev_was_simc) {
|
|
+ continue;
|
|
+ }
|
|
+ if (*(it + 1) == '/' && *(it + 2) == '/' && isalpha(*beg)) {
|
|
+ is_url = 1;
|
|
+ /* double-check: protocol must be alnum (or +) */
|
|
+ for (const char *p = beg; p != it; ++p)
|
|
+ if (!isalnum(*p) && *p != '+') {
|
|
+ is_url = 0;
|
|
+ break;
|
|
+ }
|
|
+ if (is_url)
|
|
+ continue;
|
|
+ }
|
|
+ prev_was_simc = 1;
|
|
+ subp_convert(&beg, it, is_url, dst, dstend);
|
|
+ is_url = 0;
|
|
+
|
|
+ if (*dst == dstend) {
|
|
+ system_printf("Path cut off during conversion: %s\n", orig_dst);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ **dst = ';';
|
|
+ *dst += 1;
|
|
+ }
|
|
+
|
|
+ if (*it != ':' && prev_was_simc) {
|
|
+ prev_was_simc = 0;
|
|
+ beg = it;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!prev_was_simc) {
|
|
+ subp_convert(&beg, it, is_url, dst, dstend);
|
|
+ } else {
|
|
+ *dst -= 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+int is_special_posix_path(const char* from, const char* to, char** dst, const char* dstend) {
|
|
+ const char dev_null[] = "/dev/null";
|
|
+
|
|
+ if ((to - from) == (sizeof(dev_null) - 1) && strncmp(from, "/dev/null", to - from) == 0) {
|
|
+ copy_to_dst("nul", NULL, dst, dstend);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void posix_to_win32_path(const char* from, const char* to, char** dst, const char* dstend) {
|
|
+ if ( from != to ) {
|
|
+ tmp_pathbuf tp;
|
|
+ char *one_path = tp.c_get();
|
|
+ strncpy(one_path, from, to-from);
|
|
+ one_path[to-from] = '\0';
|
|
+
|
|
+ path_conv conv (one_path, 0);
|
|
+ if (conv.error)
|
|
+ {
|
|
+ set_errno(conv.error);
|
|
+ copy_to_dst(one_path, NULL, dst, dstend);
|
|
+ } else {
|
|
+ char* win32_path = tp.c_get();
|
|
+ stpcpy (win32_path, conv.get_win32 ());
|
|
+ for (; (*win32_path != '\0') && (*dst != dstend); ++win32_path, ++(*dst)) {
|
|
+ **dst = (*win32_path == '\\') ? '/' : *win32_path;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
diff --git a/winsup/cygwin/msys2_path_conv.h b/winsup/cygwin/msys2_path_conv.h
|
|
new file mode 100644
|
|
index 0000000..67d85ec
|
|
--- /dev/null
|
|
+++ b/winsup/cygwin/msys2_path_conv.h
|
|
@@ -0,0 +1,147 @@
|
|
+/*
|
|
+ The MSYS2 Path conversion source code is licensed under:
|
|
+
|
|
+ CC0 1.0 Universal
|
|
+
|
|
+ Official translations of this legal tool are available
|
|
+
|
|
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
|
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
|
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
|
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
|
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
|
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
|
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
|
+ HEREUNDER.
|
|
+
|
|
+ Statement of Purpose
|
|
+
|
|
+ The laws of most jurisdictions throughout the world automatically
|
|
+ confer exclusive Copyright and Related Rights (defined below) upon the
|
|
+ creator and subsequent owner(s) (each and all, an "owner") of an
|
|
+ original work of authorship and/or a database (each, a "Work").
|
|
+
|
|
+ Certain owners wish to permanently relinquish those rights to a Work
|
|
+ for the purpose of contributing to a commons of creative, cultural and
|
|
+ scientific works ("Commons") that the public can reliably and without
|
|
+ fear of later claims of infringement build upon, modify, incorporate
|
|
+ in other works, reuse and redistribute as freely as possible in any
|
|
+ form whatsoever and for any purposes, including without limitation
|
|
+ commercial purposes. These owners may contribute to the Commons to
|
|
+ promote the ideal of a free culture and the further production of
|
|
+ creative, cultural and scientific works, or to gain reputation or
|
|
+ greater distribution for their Work in part through the use and
|
|
+ efforts of others.
|
|
+
|
|
+ For these and/or other purposes and motivations, and without any
|
|
+ expectation of additional consideration or compensation, the person
|
|
+ associating CC0 with a Work (the "Affirmer"), to the extent that he or
|
|
+ she is an owner of Copyright and Related Rights in the Work,
|
|
+ voluntarily elects to apply CC0 to the Work and publicly distribute
|
|
+ the Work under its terms, with knowledge of his or her Copyright and
|
|
+ Related Rights in the Work and the meaning and intended legal effect
|
|
+ of CC0 on those rights.
|
|
+
|
|
+ 1. Copyright and Related Rights. A Work made available under CC0 may
|
|
+ be protected by copyright and related or neighboring rights
|
|
+ ("Copyright and Related Rights"). Copyright and Related Rights
|
|
+ include, but are not limited to, the following:
|
|
+
|
|
+ the right to reproduce, adapt, distribute, perform, display,
|
|
+ communicate, and translate a Work;
|
|
+ moral rights retained by the original author(s) and/or performer(s);
|
|
+ publicity and privacy rights pertaining to a person's image or
|
|
+ likeness depicted in a Work;
|
|
+ rights protecting against unfair competition in regards to a Work,
|
|
+ subject to the limitations in paragraph 4(a), below;
|
|
+ rights protecting the extraction, dissemination, use and reuse of data
|
|
+ in a Work;
|
|
+ database rights (such as those arising under Directive 96/9/EC of the
|
|
+ European Parliament and of the Council of 11 March 1996 on the legal
|
|
+ protection of databases, and under any national implementation
|
|
+ thereof, including any amended or successor version of such
|
|
+ directive); and
|
|
+ other similar, equivalent or corresponding rights throughout the world
|
|
+ based on applicable law or treaty, and any national implementations
|
|
+ thereof.
|
|
+
|
|
+ 2. Waiver. To the greatest extent permitted by, but not in
|
|
+ contravention of, applicable law, Affirmer hereby overtly, fully,
|
|
+ permanently, irrevocably and unconditionally waives, abandons, and
|
|
+ surrenders all of Affirmer's Copyright and Related Rights and
|
|
+ associated claims and causes of action, whether now known or unknown
|
|
+ (including existing as well as future claims and causes of action), in
|
|
+ the Work (i) in all territories worldwide, (ii) for the maximum
|
|
+ duration provided by applicable law or treaty (including future time
|
|
+ extensions), (iii) in any current or future medium and for any number
|
|
+ of copies, and (iv) for any purpose whatsoever, including without
|
|
+ limitation commercial, advertising or promotional purposes (the
|
|
+ "Waiver"). Affirmer makes the Waiver for the benefit of each member of
|
|
+ the public at large and to the detriment of Affirmer's heirs and
|
|
+ successors, fully intending that such Waiver shall not be subject to
|
|
+ revocation, rescission, cancellation, termination, or any other legal
|
|
+ or equitable action to disrupt the quiet enjoyment of the Work by the
|
|
+ public as contemplated by Affirmer's express Statement of Purpose.
|
|
+
|
|
+ 3. Public License Fallback. Should any part of the Waiver for any
|
|
+ reason be judged legally invalid or ineffective under applicable law,
|
|
+ then the Waiver shall be preserved to the maximum extent permitted
|
|
+ taking into account Affirmer's express Statement of Purpose. In
|
|
+ addition, to the extent the Waiver is so judged Affirmer hereby grants
|
|
+ to each affected person a royalty-free, non transferable, non
|
|
+ sublicensable, non exclusive, irrevocable and unconditional license to
|
|
+ exercise Affirmer's Copyright and Related Rights in the Work (i) in
|
|
+ all territories worldwide, (ii) for the maximum duration provided by
|
|
+ applicable law or treaty (including future time extensions), (iii) in
|
|
+ any current or future medium and for any number of copies, and (iv)
|
|
+ for any purpose whatsoever, including without limitation commercial,
|
|
+ advertising or promotional purposes (the "License"). The License shall
|
|
+ be deemed effective as of the date CC0 was applied by Affirmer to the
|
|
+ Work. Should any part of the License for any reason be judged legally
|
|
+ invalid or ineffective under applicable law, such partial invalidity
|
|
+ or ineffectiveness shall not invalidate the remainder of the License,
|
|
+ and in such case Affirmer hereby affirms that he or she will not (i)
|
|
+ exercise any of his or her remaining Copyright and Related Rights in
|
|
+ the Work or (ii) assert any associated claims and causes of action
|
|
+ with respect to the Work, in either case contrary to Affirmer's
|
|
+ express Statement of Purpose.
|
|
+
|
|
+ 4. Limitations and Disclaimers.
|
|
+
|
|
+ No trademark or patent rights held by Affirmer are waived, abandoned,
|
|
+ surrendered, licensed or otherwise affected by this document.
|
|
+ Affirmer offers the Work as-is and makes no representations or
|
|
+ warranties of any kind concerning the Work, express, implied,
|
|
+ statutory or otherwise, including without limitation warranties of
|
|
+ title, merchantability, fitness for a particular purpose, non
|
|
+ infringement, or the absence of latent or other defects, accuracy, or
|
|
+ the present or absence of errors, whether or not discoverable, all to
|
|
+ the greatest extent permissible under applicable law.
|
|
+ Affirmer disclaims responsibility for clearing rights of other persons
|
|
+ that may apply to the Work or any use thereof, including without
|
|
+ limitation any person's Copyright and Related Rights in the Work.
|
|
+ Further, Affirmer disclaims responsibility for obtaining any necessary
|
|
+ consents, permissions or other rights required for any use of the
|
|
+ Work.
|
|
+ Affirmer understands and acknowledges that Creative Commons is not a
|
|
+ party to this document and has no duty or obligation with respect to
|
|
+ this CC0 or use of the Work.
|
|
+
|
|
+ Contributions thanks to:
|
|
+ niXman <i.nixman@autistici.org>
|
|
+ Ely Arzhannikov <iarzhannikov@gmail.com>
|
|
+ Alexey Pavlov <alexpux@gmail.com>
|
|
+ Ray Donnelly <mingw.android@gmail.com>
|
|
+ Johannes Schindelin <johannes.schindelin@gmx.de>
|
|
+
|
|
+*/
|
|
+
|
|
+#ifndef PATH_CONV_H_DB4IQBH3
|
|
+#define PATH_CONV_H_DB4IQBH3
|
|
+
|
|
+#include <stdlib.h>
|
|
+
|
|
+const char* convert(char *dst, size_t dstlen, const char *src);
|
|
+
|
|
+#endif /* end of include guard: PATH_CONV_H_DB4IQBH3 */
|
|
+
|
|
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
|
|
index f3b9913..7ffb5bc 100644
|
|
--- a/winsup/cygwin/path.cc
|
|
+++ b/winsup/cygwin/path.cc
|
|
@@ -66,6 +66,7 @@
|
|
#include "shared_info.h"
|
|
#include "tls_pbuf.h"
|
|
#include "environ.h"
|
|
+#include "msys2_path_conv.h"
|
|
#undef basename
|
|
|
|
suffix_info stat_suffixes[] =
|
|
@@ -3602,6 +3603,74 @@ fchdir (int fd)
|
|
return res;
|
|
}
|
|
|
|
+//
|
|
+// Important: If returned pointer == arg, then this function
|
|
+// did not malloc that pointer; otherwise free it.
|
|
+//
|
|
+extern "C" char *
|
|
+arg_heuristic_with_exclusions (char const * const arg, char const * exclusions, size_t exclusions_count)
|
|
+{
|
|
+ char *arg_result;
|
|
+
|
|
+ // Must return something ..
|
|
+ size_t arglen = (arg ? strlen (arg): 0);
|
|
+
|
|
+ if (arglen == 0 || !arg)
|
|
+ {
|
|
+ arg_result = (char *)malloc (sizeof (char));
|
|
+ arg_result[0] = '\0';
|
|
+ return arg_result;
|
|
+ }
|
|
+
|
|
+ debug_printf("Input value: (%s)", arg);
|
|
+ for (size_t excl = 0; excl < exclusions_count; ++excl)
|
|
+ {
|
|
+ /* Since we've got regex linked we should maybe switch to that, but
|
|
+ running regexes for every argument could be too slow. */
|
|
+ if ( strcmp (exclusions, "*") == 0 || (strlen (exclusions) && strstr (arg, exclusions) == arg) )
|
|
+ return (char*)arg;
|
|
+ exclusions += strlen (exclusions) + 1;
|
|
+ }
|
|
+
|
|
+ // Leave enough room for at least 16 path elements; we might be converting
|
|
+ // a path list.
|
|
+ size_t stack_len = arglen + 16 * MAX_PATH;
|
|
+ char * stack_path = (char *)malloc (stack_len);
|
|
+ if (!stack_path)
|
|
+ {
|
|
+ debug_printf ("out of stack space?");
|
|
+ return (char *)arg;
|
|
+ }
|
|
+ memset (stack_path, 0, MAX_PATH);
|
|
+ convert (stack_path, stack_len - 1, arg);
|
|
+ debug_printf ("convert()'ed: %s (length %d)\n.....->: %s", arg, arglen, stack_path);
|
|
+ // Don't allocate memory if no conversion happened.
|
|
+ if (!strcmp (arg, stack_path))
|
|
+ {
|
|
+ if (arg != stack_path)
|
|
+ {
|
|
+ free (stack_path);
|
|
+ }
|
|
+ return ((char *)arg);
|
|
+ }
|
|
+ arg_result = (char *)realloc (stack_path, strlen (stack_path)+1);
|
|
+ // Windows doesn't like empty entries in PATH env. variables (;;)
|
|
+ char* semisemi = strstr(arg_result, ";;");
|
|
+ while (semisemi)
|
|
+ {
|
|
+ memmove(semisemi, semisemi+1, strlen(semisemi));
|
|
+ semisemi = strstr(semisemi, ";;");
|
|
+ }
|
|
+ return arg_result;
|
|
+}
|
|
+
|
|
+extern "C" char *
|
|
+arg_heuristic (char const * const arg)
|
|
+{
|
|
+ return arg_heuristic_with_exclusions (arg, NULL, 0);
|
|
+}
|
|
+
|
|
+
|
|
/******************** Exported Path Routines *********************/
|
|
|
|
/* Cover functions to the path conversion routines.
|
|
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
|
|
index af177c0..e7a0810 100644
|
|
--- a/winsup/cygwin/spawn.cc
|
|
+++ b/winsup/cygwin/spawn.cc
|
|
@@ -284,6 +284,27 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
|
|
}
|
|
}
|
|
|
|
+ /* Environment variable MSYS2_ARG_CONV_EXCL contains a list
|
|
+ of ';' separated argument prefixes to pass un-modified..
|
|
+ It isn't applied to env. variables; only spawn arguments.
|
|
+ A value of * means don't convert any arguments. */
|
|
+ char* msys2_arg_conv_excl_env = getenv("MSYS2_ARG_CONV_EXCL");
|
|
+ char* msys2_arg_conv_excl = NULL;
|
|
+ size_t msys2_arg_conv_excl_count = 0;
|
|
+ if (msys2_arg_conv_excl_env)
|
|
+ {
|
|
+ msys2_arg_conv_excl = (char*)alloca (strlen(msys2_arg_conv_excl_env)+1);
|
|
+ strcpy (msys2_arg_conv_excl, msys2_arg_conv_excl_env);
|
|
+ msys2_arg_conv_excl_count = 1;
|
|
+ msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl, ';' );
|
|
+ while (msys2_arg_conv_excl_env)
|
|
+ {
|
|
+ *msys2_arg_conv_excl_env = '\0';
|
|
+ ++msys2_arg_conv_excl_count;
|
|
+ msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl_env + 1, ';' );
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Check if we have been called from exec{lv}p or spawn{lv}p and mask
|
|
mode to keep only the spawn mode. */
|
|
bool p_type_exec = !!(mode & _P_PATH_TYPE_EXEC);
|
|
@@ -393,12 +414,26 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
|
|
moreinfo->argc = newargv.argc;
|
|
moreinfo->argv = newargv;
|
|
}
|
|
- if ((wincmdln || !real_path.iscygexec ())
|
|
- && !cmd.fromargv (newargv, real_path.get_win32 (),
|
|
- real_path.iscygexec ()))
|
|
+ else
|
|
{
|
|
- res = -1;
|
|
- __leave;
|
|
+ for (int i = 0; i < newargv.argc; i++)
|
|
+ {
|
|
+ //convert argv to win32
|
|
+ int newargvlen = strlen (newargv[i]);
|
|
+ char *tmpbuf = (char *)malloc (newargvlen + 1);
|
|
+ memcpy (tmpbuf, newargv[i], newargvlen + 1);
|
|
+ tmpbuf = arg_heuristic_with_exclusions(tmpbuf, msys2_arg_conv_excl, msys2_arg_conv_excl_count);
|
|
+ debug_printf("newargv[%d] = %s", i, newargv[i]);
|
|
+ newargv.replace (i, tmpbuf);
|
|
+ free (tmpbuf);
|
|
+ }
|
|
+ if ((wincmdln || !real_path.iscygexec ())
|
|
+ && !cmd.fromargv (newargv, real_path.get_win32 (),
|
|
+ real_path.iscygexec ()))
|
|
+ {
|
|
+ res = -1;
|
|
+ __leave;
|
|
+ }
|
|
}
|
|
|
|
|
|
@@ -522,7 +557,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
|
|
moreinfo->envp = build_env (envp, envblock, moreinfo->envc,
|
|
real_path.iscygexec (),
|
|
switch_user ? ::cygheap->user.primary_token ()
|
|
- : NULL);
|
|
+ : NULL,
|
|
+ real_path.iscygexec ());
|
|
if (!moreinfo->envp || !envblock)
|
|
{
|
|
set_errno (E2BIG);
|
|
diff --git a/winsup/cygwin/winf.h b/winsup/cygwin/winf.h
|
|
index e3a65f8..1aeec8d 100644
|
|
--- a/winsup/cygwin/winf.h
|
|
+++ b/winsup/cygwin/winf.h
|
|
@@ -51,6 +51,10 @@ class av
|
|
calloced = 1;
|
|
}
|
|
}
|
|
+ void replace (int i, const char *arg)
|
|
+ {
|
|
+ argv[i] = cstrdup1 (arg);
|
|
+ }
|
|
void dup_all ()
|
|
{
|
|
for (int i = calloced; i < argc; i++)
|
|
--
|
|
2.28.0
|
|
|