@@ -2217,7 +2217,7 @@ doConnStrQuoting(PQExpBuffer buf, const char *str)
22172217
22182218/*
22192219 * Append the given string to the shell command being built in the buffer,
2220- * with suitable shell-style quoting.
2220+ * with suitable shell-style quoting to create exactly one argument .
22212221 *
22222222 * Forbid LF or CR characters, which have scant practical use beyond designing
22232223 * security breaches. The Windows command shell is unusable as a conduit for
@@ -2249,8 +2249,20 @@ doShellQuoting(PQExpBuffer buf, const char *str)
22492249}
22502250appendPQExpBufferChar (buf ,'\'' );
22512251#else /* WIN32 */
2252+ int backslash_run_length = 0 ;
22522253
2253- appendPQExpBufferChar (buf ,'"' );
2254+ /*
2255+ * A Windows system() argument experiences two layers of interpretation.
2256+ * First, cmd.exe interprets the string. Its behavior is undocumented,
2257+ * but a caret escapes any byte except LF or CR that would otherwise have
2258+ * special meaning. Handling of a caret before LF or CR differs between
2259+ * "cmd.exe /c" and other modes, and it is unusable here.
2260+ *
2261+ * Second, the new process parses its command line to construct argv (see
2262+ * https://msdn.microsoft.com/en-us/library/17w5ykft.aspx). This treats
2263+ * backslash-double quote sequences specially.
2264+ */
2265+ appendPQExpBufferStr (buf ,"^\"" );
22542266for (p = str ;* p ;p ++ )
22552267{
22562268if (* p == '\n' || * p == '\r' )
@@ -2261,11 +2273,41 @@ doShellQuoting(PQExpBuffer buf, const char *str)
22612273exit (EXIT_FAILURE );
22622274}
22632275
2276+ /* Change N backslashes before a double quote to 2N+1 backslashes. */
22642277if (* p == '"' )
2265- appendPQExpBufferStr (buf ,"\\\"" );
2278+ {
2279+ while (backslash_run_length )
2280+ {
2281+ appendPQExpBufferStr (buf ,"^\\" );
2282+ backslash_run_length -- ;
2283+ }
2284+ appendPQExpBufferStr (buf ,"^\\" );
2285+ }
2286+ else if (* p == '\\' )
2287+ backslash_run_length ++ ;
22662288else
2267- appendPQExpBufferChar (buf ,* p );
2289+ backslash_run_length = 0 ;
2290+
2291+ /*
2292+ * Decline to caret-escape the most mundane characters, to ease
2293+ * debugging and lest we approach the command length limit.
2294+ */
2295+ if (!((* p >='a' && * p <='z' )||
2296+ (* p >='A' && * p <='Z' )||
2297+ (* p >='0' && * p <='9' )))
2298+ appendPQExpBufferChar (buf ,'^' );
2299+ appendPQExpBufferChar (buf ,* p );
2300+ }
2301+
2302+ /*
2303+ * Change N backslashes at end of argument to 2N backslashes, because they
2304+ * precede the double quote that terminates the argument.
2305+ */
2306+ while (backslash_run_length )
2307+ {
2308+ appendPQExpBufferStr (buf ,"^\\" );
2309+ backslash_run_length -- ;
22682310}
2269- appendPQExpBufferChar (buf ,'"' );
2311+ appendPQExpBufferStr (buf ,"^\"" );
22702312#endif /* WIN32 */
22712313}