@@ -1904,7 +1904,7 @@ doConnStrQuoting(PQExpBuffer buf, const char *str)
1904
1904
1905
1905
/*
1906
1906
* Append the given string to the shell command being built in the buffer,
1907
- * with suitable shell-style quoting.
1907
+ * with suitable shell-style quoting to create exactly one argument .
1908
1908
*
1909
1909
* Forbid LF or CR characters, which have scant practical use beyond designing
1910
1910
* security breaches. The Windows command shell is unusable as a conduit for
@@ -1936,8 +1936,20 @@ doShellQuoting(PQExpBuffer buf, const char *str)
1936
1936
}
1937
1937
appendPQExpBufferChar (buf , '\'' );
1938
1938
#else /* WIN32 */
1939
+ int backslash_run_length = 0 ;
1939
1940
1940
- appendPQExpBufferChar (buf , '"' );
1941
+ /*
1942
+ * A Windows system() argument experiences two layers of interpretation.
1943
+ * First, cmd.exe interprets the string. Its behavior is undocumented,
1944
+ * but a caret escapes any byte except LF or CR that would otherwise have
1945
+ * special meaning. Handling of a caret before LF or CR differs between
1946
+ * "cmd.exe /c" and other modes, and it is unusable here.
1947
+ *
1948
+ * Second, the new process parses its command line to construct argv (see
1949
+ * https://msdn.microsoft.com/en-us/library/17w5ykft.aspx). This treats
1950
+ * backslash-double quote sequences specially.
1951
+ */
1952
+ appendPQExpBufferStr (buf , "^\"" );
1941
1953
for (p = str ; * p ; p ++ )
1942
1954
{
1943
1955
if (* p == '\n' || * p == '\r' )
@@ -1948,11 +1960,41 @@ doShellQuoting(PQExpBuffer buf, const char *str)
1948
1960
exit (EXIT_FAILURE );
1949
1961
}
1950
1962
1963
+ /* Change N backslashes before a double quote to 2N+1 backslashes. */
1951
1964
if (* p == '"' )
1952
- appendPQExpBuffer (buf , "\\\"" );
1965
+ {
<
104B6
/code>
1966
+ while (backslash_run_length )
1967
+ {
1968
+ appendPQExpBufferStr (buf , "^\\" );
1969
+ backslash_run_length -- ;
1970
+ }
1971
+ appendPQExpBufferStr (buf , "^\\" );
1972
+ }
1973
+ else if (* p == '\\' )
1974
+ backslash_run_length ++ ;
1953
1975
else
1954
- appendPQExpBufferChar (buf , * p );
1976
+ backslash_run_length = 0 ;
1977
+
1978
+ /*
1979
+ * Decline to caret-escape the most mundane characters, to ease
1980
+ * debugging and lest we approach the command length limit.
1981
+ */
1982
+ if (!((* p >= 'a' && * p <= 'z' ) ||
1983
+ (* p >= 'A' && * p <= 'Z' ) ||
1984
+ (* p >= '0' && * p <= '9' )))
1985
+ appendPQExpBufferChar (buf , '^' );
1986
+ appendPQExpBufferChar (buf , * p );
1987
+ }
1988
+
1989
+ /*
1990
+ * Change N backslashes at end of argument to 2N backslashes, because they
1991
+ * precede the double quote that terminates the argument.
1992
+ */
1993
+ while (backslash_run_length )
1994
+ {
1995
+ appendPQExpBufferStr (buf , "^\\" );
1996
+ backslash_run_length -- ;
1955
1997
}
1956
- appendPQExpBufferChar (buf , '"' );
1998
+ appendPQExpBufferStr (buf , "^\"" );
1957
1999
#endif /* WIN32 */
1958
2000
}
0 commit comments