diff -Naur a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in --- a/winsup/cygwin/Makefile.in 2014-03-21 19:20:47.170200000 +0400 +++ b/winsup/cygwin/Makefile.in 2014-03-21 00:16:31.613800000 +0400 @@ -169,8 +169,8 @@ glob_pattern_p.o globals.o grp.o heap.o hookapi.o inet_addr.o \ inet_network.o init.o ioctl.o ipc.o kernel32.o ldap.o libstdcxx_wrapper.o \ localtime.o lsearch.o malloc_wrapper.o minires-os-if.o minires.o \ - miscfuncs.o mktemp.o mmap.o msg.o mount.o net.o netdb.o nfs.o nftw.o \ - nlsfuncs.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o posix_ipc.o \ + miscfuncs.o mktemp.o mmap.o msg.o msys2_path_conv.o mount.o net.o netdb.o nfs.o \ + nftw.o nlsfuncs.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o posix_ipc.o \ pseudo-reloc.o pthread.o random.o regcomp.o regerror.o regexec.o regfree.o \ registry.o resource.o rexec.o rcmd.o scandir.o sched.o sec_acl.o \ sec_auth.o sec_helper.o security.o select.o sem.o setlsapwd.o shared.o \ diff -Naur a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc --- a/winsup/cygwin/msys2_path_conv.cc 1970-01-01 03:00:00.000000000 +0300 +++ b/winsup/cygwin/msys2_path_conv.cc 2014-03-21 20:53:18.963200000 +0400 @@ -0,0 +1,602 @@ +/* + 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 + Ely Arzhannikov + Alexey Pavlov + Ray Donnelly + +*/ + +#include "winsup.h" +#include "miscfuncs.h" +#include +#include +#include +#include +#include +#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 +#include +#include +#include + +#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** to, int* in_string) { + 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(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; + } + } + + char* dstit = dst; + char* dstend = dst + dstlen; + if (!need_convert) { + copy_to_dst(src, NULL, &dstit, dstend); + *dstit = '\0'; + return dst; + } + + 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; + } + } + + sub_convert(&srcbeg, &srcit, &dstit, dstend, &in_string); + + 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 (!isalpha(*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 == '.' && (*(it + 1) == '.' || *(it + 1) == '/')) { + return RELATIVE_PATH; + } + + if (*it == '/') { + it += 1; + + if (isalpha(*it) && *(it + 1) == ':') { + return ESCAPE_WINDOWS_PATH; + } + + if (*it == '.' && *(it + 1) == '.') { + return SIMPLE_WINDOWS_PATH; + } + + int double_slashed = 0; + if (*it == '/') { + double_slashed = 1; + it += 1; + } + + if (double_slashed && *it == ':') { + return URL; + } + + + for (; *it != '\0' && it != end; ++it) { + switch(*it) { + case ':': {char ch = *(it + 1); if (ch == '/' || ch == ':' || ch == '.') return POSIX_PATH_LIST;} + case '/': result = (double_slashed) ? UNC : ROOTED_PATH; break; + case ';': return WINDOWS_PATH_LIST; + } + } + + if (result != NONE) { + return result; + } + + return (double_slashed) ? ESCAPED_PATH : ROOTED_PATH; + } + + int starts_with_minus = (*it == '-'); + + if (starts_with_minus) { + char n2 = *(it + 2); + char n3 = n2 ? *(it + 3) : '\0'; + char n4 = n3 ? *(it + 4) : '\0'; + char n5 = n4 ? *(it + 5) : '\0'; + + if (n2 == '/') { + it += 2; + result = ROOTED_PATH; + } else if ((n2 == '\'' || n2 == '"') && n3 == '/') { + it += 3; + result = ROOTED_PATH; + } + + if (isalpha(n2) && n3 == ':' && n4 == '/') { + *src = it + 2; + return SIMPLE_WINDOWS_PATH; + } + + if ((n2 == '\'' || n2 == '"') && isalpha(n3) && n4 == ':' && n5 == '/') { + *src = it + 3; + return SIMPLE_WINDOWS_PATH; + } + } + + for (const char* it2 = it; *it2 != '\0' && it2 != end; ++it2) { + char ch = *it2; + if (ch == '=') { + *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; + ch = *it2; + if (ch == '/' || ch == ':' || ch == '.') { + if (ch == '/' && *(it2 + 1) == '/') { + return URL; + } else { + return POSIX_PATH_LIST; + } + } else { + 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 (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 = 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* 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) == '/') { + is_url = 1; + continue; + } + prev_was_simc = 1; + subp_convert(&beg, it, is_url, dst, dstend); + is_url = 0; + + **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 -Naur a/winsup/cygwin/msys2_path_conv.h b/winsup/cygwin/msys2_path_conv.h --- a/winsup/cygwin/msys2_path_conv.h 1970-01-01 03:00:00.000000000 +0300 +++ b/winsup/cygwin/msys2_path_conv.h 2014-03-21 15:45:14.721000000 +0400 @@ -0,0 +1,146 @@ +/* + 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 + Ely Arzhannikov + Alexey Pavlov + Ray Donnelly + +*/ + +#ifndef PATH_CONV_H_DB4IQBH3 +#define PATH_CONV_H_DB4IQBH3 + +#include + +const char* convert(char *dst, size_t dstlen, const char *src); + +#endif /* end of include guard: PATH_CONV_H_DB4IQBH3 */ + diff -Naur a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc --- a/winsup/cygwin/path.cc 2014-03-21 19:20:52.131000000 +0400 +++ b/winsup/cygwin/path.cc 2014-03-21 20:54:31.097600000 +0400 @@ -65,6 +65,7 @@ #include "cygtls.h" #include "tls_pbuf.h" #include "environ.h" +#include "msys2_path_conv.h" #include #include #include @@ -3344,84 +3345,26 @@ return res; } -static bool -isabswinpath (const char * path) -{ - int plen = strlen (path); - bool p0alpha = isalpha (path[0]) != 0; - bool p1colon = (plen > 1 && path[1] == ':'); - bool rval = - ( ((plen == 2) && p0alpha && p1colon) - || ( (plen > 2) - && p0alpha - && p1colon - && (strchr (&path[2], ':') == (char *)NULL) - ) - || ( plen > 3 - && path[0] == '\\' - && path[1] == '\\' - && path[3] == '\\' - ) - ); - return rval; -} - -static char * -ScrubRetpath (char * const retpath) -{ - char * sspath = (char *)retpath; - // - // Check for null path because Win32 doesn't like them. - // I.E.: Path lists of c:/foo;;c:/bar need changed to - // c:/foo;c:/bar. - // - // This need be executed only if we actually converted the path. - // - while (*sspath) - { - if (*sspath == ';' && sspath[1] == ';') - for (char *i = sspath; *i; i++) - *i = *(i + 1); - else - sspath++; - } - if (*(sspath - 1) == ';') - *(sspath - 1) = '\0'; - - // - // If we modified the path then convert all / to \ if we have a path list - // else convert all \ to /. - // - if ((strchr (retpath, ';'))) - { - backslashify (retpath, retpath, 0); - } else - { - slashify (retpath, retpath, 0); - } - debug_printf("returning: %s", retpath); - return retpath; -} - // -// The returned pointer should be freed with free unless, -// as it turns out, it is equal to the input pointer. +// 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; - int arglen = (arg ? strlen (arg): 0); + // Must return something .. + size_t arglen = (arg ? strlen (arg): 0); - if (arglen == 0) + if (arglen == 0 || !arg) { - char *retpath = (char *)malloc (sizeof (char)); - memset (retpath, 0, sizeof (char)); - return retpath; + 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) { if ( strstr (arg, exclusions) == arg ) @@ -3429,408 +3372,31 @@ exclusions += strlen (exclusions) + 1; } - // - // copy of the path string that we can overwrite - // - char *spath = (char *)alloca (arglen + 1); - memcpy (spath, arg, arglen + 1); - - char * sspath; - - // - // retpath contains the converted path string to be returned - // - char *retpath = (char *)malloc(((MAX_PATH - arglen) > 0) ? - MAX_PATH : arglen + MAX_PATH); - memset (retpath, 0, MAX_PATH); - int retpath_len = 0; - int retpath_buflen = MAX_PATH; - -#define retpathcat(retstr) \ - retpath_len += strlen(retstr); \ - if (retpath_buflen <= retpath_len) \ - { \ - retpath_buflen = ((retpath_buflen * 2 <= retpath_len) ? \ - retpath_len + 1 : retpath_buflen * 2); \ - retpath = (char *)realloc (retpath, retpath_buflen); \ - } \ - strcat (retpath, retstr); - -#define retpathcpy(retstr) \ - retpath_len = strlen (retstr); \ - *retpath = '\0'; \ - if (retpath_buflen <= retpath_len ) \ - { \ - retpath_buflen = ((retpath_buflen * 2 <= retpath_len) ? \ - retpath_len + 1 : retpath_buflen * 2); \ - retpath = (char *)realloc (retpath, retpath_buflen); \ - } \ - strcpy (retpath, retstr); - - // - // Just return win32 paths and path lists. - // - if (isabswinpath (arg) - || (strchr (arg, ';') > 0) - ) + size_t stack_len = arglen + MAX_PATH; + char * stack_path = (char *)malloc (stack_len); + memset (stack_path, 0, MAX_PATH); + if (!stack_len) + { + debug_printf ("out of stack space?"); + return (char *)arg; + } + 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)) { - debug_printf("returning Win32 absolute path: %s", arg); return ((char *)arg); } - // - // Multiple forward slashes are treated special, - // Remove one and return for the form of //foo or ///bar - // but just return for the form of //server/share. - // - else if (arg[0] == '/' && arg[1] == '/') - { - int tidx = 2; - while (spath[tidx] && spath[tidx] == '/') - tidx++; - if (strchr (&spath[tidx], '/')) - { - retpathcpy (spath); - } - else - { - retpathcpy (&spath[1]); - } - return ScrubRetpath (retpath); - } - // - // special case confusion elimination - // Translate a path that looks similar to /c: to c:/. - // - else if (arg[0] == '/' && isabswinpath (arg + 1)) - { - retpathcpy (&arg[1]); - return ScrubRetpath (retpath); - } - // - // Check for variable set. - // - else if ((sspath = strchr(spath, '=')) && isalpha (spath[0])) - { - if (isabswinpath (sspath + 1)) { - debug_printf("returning: %s", arg); - return (char *)arg; - } - char *swin32_path = arg_heuristic(sspath + 1); - if (swin32_path == (sspath + 1)) { - debug_printf("returning: %s", arg); - return (char *)arg; - } - *sspath = '\0'; - retpathcpy (spath); - retpathcat ("="); - retpathcat (swin32_path); - free (swin32_path); - return ScrubRetpath (retpath); - } - // - // Check for paths after commas, if string begins with a '-' character. - // - else if ((sspath = strchr(spath, ',')) && spath[0] == '-') - { - if (isabswinpath (sspath + 1)) { - debug_printf("returning: %s", arg); - return (char *)arg; - } - char *swin32_path = arg_heuristic(sspath + 1); - if (swin32_path == (sspath + 1)) { - debug_printf("returning: %s", arg); - return (char *)arg; - } - *sspath = '\0'; - retpathcpy (spath); - retpathcat (","); - retpathcat (swin32_path); - free (swin32_path); - return ScrubRetpath (retpath); - } - // - // Check for POSIX path lists. - // But we have to allow processing of quoted strings and switches first - // which uses recursion so this code will be seen again. - // - else - { - sspath = strchr (spath, ':'); - // - // Prevent http://some.string/ from being modified. - // - if ((sspath > 0 && strlen (sspath) > 2) - && (sspath[1] == '/') - && (sspath[2] == '/') - ) - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - else - if ((sspath > 0) - && (strchr (spath, '/') > 0) - // - // Prevent strings beginning with -, ", ', or @ from being processed, - // remember that this is a recursive routine. - // - && (strchr ("-\"\'@", spath[0]) == 0) - // - // Prevent ``foo:echo /bar/baz'' from being considered a path list. - // - && (strlen (sspath) > 1 && strchr (":./", sspath[1]) > 0) - ) - { - // - // Yes, convert to Win32 path list. - // - while (sspath) - { - *sspath = '\0'; - char *swin32_path = arg_heuristic (spath); - // - // Just ignore sret; swin32_path has the value we need. - // - retpathcat (swin32_path); - if (swin32_path != spath) - free (swin32_path); - spath = sspath + 1; - sspath = strchr (spath, ':'); - retpathcat (";"); - // - // Handle the last path in the list. - // - if (!sspath) - { - char *swin32_path = arg_heuristic (spath); - retpathcat (swin32_path); - if (swin32_path != spath) - free (swin32_path); - } - } - return ScrubRetpath (retpath); - } - else + arg_result = (char *)malloc (strlen (stack_path)+1); + strcpy (arg_result, stack_path); + // Windows doesn't like empty entries in PATH env. variables (;;) + char* semisemi = strstr(arg_result, ";;"); + while (semisemi) { - switch (spath[0]) - { - case '/': - // - // Just a normal POSIX path. - // - { - // - // Convert only up to a ".." path component, and - // keep all what follows as is. - // - sspath = strstr (spath, "/.."); - if (sspath) - { - *sspath = '\0'; - char *swin32_path = arg_heuristic (spath); - if (swin32_path == spath) - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - retpathcpy (swin32_path); - retpathcat ("/"); - retpathcat (sspath+1); - free (swin32_path); - return ScrubRetpath (retpath); - } - if (strcmp(spath, "/dev/null") == 0) - { - retpathcpy("nul"); - return ScrubRetpath (retpath); - } - path_conv p (spath, 0); - if (p.error) - { - set_errno(p.error); - debug_printf("returning: %s", arg); - return ((char *)arg); - } - retpathcpy (p.get_win32 ()); - return ScrubRetpath (retpath); - } - case '-': - // - // here we check for POSIX paths as attributes to a POSIX switch. - // - sspath = strchr (spath, '='); - if (sspath) - { - // - // just use recursion if we find a set variable token. - // - *sspath = '\0'; - if (isabswinpath (sspath + 1)) { - debug_printf("returning: %s", arg); - return (char *)arg; - } - char *swin32_path = arg_heuristic(sspath + 1); - if (swin32_path == sspath + 1) - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - retpathcpy (spath); - retpathcat ("="); - retpathcat (swin32_path); - free (swin32_path); - return ScrubRetpath (retpath); - } - else - { - // - // Check for single letter option with a - // path argument attached, eg -I/include */ - // - if (spath[1] && spath[2] == '/') - { - debug_printf("spath = %s", spath); - sspath = spath + 2; - char *swin32_path = arg_heuristic (sspath); - if (swin32_path == sspath) - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - sspath = (char *)spath; - sspath++; - sspath++; - *sspath = '\0'; - retpathcpy (spath); - *sspath = '/'; - retpathcat (swin32_path); - free (swin32_path); - return ScrubRetpath (retpath); - } - else - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - } - break; - case '@': - // - // here we check for POSIX paths as attributes to a response - // file argument (@file). This is specifically to support - // MinGW binutils and gcc. - // - sspath = spath + 1; - if (isabswinpath (sspath)) - { - debug_printf("returning: %s", arg); - return (char *)arg; - } - if (spath[1] == '/') - { - debug_printf("spath = %s", spath); - char *swin32_path = arg_heuristic (sspath); - if (swin32_path == sspath) - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - sspath = (char *)spath; - sspath++; - *sspath = '\0'; - retpathcpy (spath); - *sspath = '/'; - retpathcat (swin32_path); - free (swin32_path); - return ScrubRetpath (retpath); - } - else - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - break; - case '"': - // - // Handle a double quote case. - // - debug_printf ("spath: %s", spath); - if (spath[1] == '/') - { - retpathcpy ("\""); - char *tpath = strchr(&spath[1], '"'); - if (tpath) - *tpath = (char)NULL; - char *swin32_path = arg_heuristic (&spath[1]); - if (swin32_path == &spath[1]) - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - retpathcat (swin32_path); - free (swin32_path); - if (tpath) - retpathcat ("\""); - return ScrubRetpath (retpath); - } - debug_printf("returning: %s", arg); - return ((char *)arg); - case '\'': - // - // Handle a single quote case. - // - debug_printf ("spath: %s", spath); - if (spath[1] == '/') - { - retpathcpy ("'"); - char *tpath = strchr(&spath[1], '\''); - if (tpath) - *tpath = (char)NULL; - char *swin32_path = arg_heuristic (&spath[1]); - if (swin32_path == &spath[1]) - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - retpathcat (swin32_path); - free (swin32_path); - if (tpath) - retpathcat ("'"); - return ScrubRetpath (retpath); - } - debug_printf("returning: %s", arg); - return ((char *)arg); - default: - // - // This takes care of variable_foo=/bar/baz - // - if ((sspath = strchr(spath, '=')) && (sspath[1] == '/')) - { - sspath[1] = '\0'; - retpathcpy (spath); - sspath[1] = '/'; - char *swin32_path = arg_heuristic (&sspath[1]); - if (swin32_path == &sspath[1]) - { - debug_printf("returning: %s", arg); - return ((char *)arg); - } - retpathcat (swin32_path); - free (swin32_path); - return ScrubRetpath (retpath); - } - // - // Oh well, nothing special found, set win32_path same as path. - // - debug_printf("returning: %s", arg); - return ((char *)arg); - } - } - } - // I should not get to this point. - assert (false); - debug_printf("returning: %s", arg); - return ScrubRetpath (retpath); + memmove(semisemi, semisemi+1, strlen(semisemi)); + semisemi = strstr(semisemi, ";;"); + } + return arg_result; } extern "C" char *