@@ -191,6 +191,21 @@ fn supervise_stderr(
191
191
ReadStdoutFailOnError { read : stdout, recv }
192
192
}
193
193
194
+ /// Transforms the given value to be suitable for use as an argument for Bourne shells by wrapping in single quotes
195
+ fn to_single_quoted ( mut value : & [ u8 ] ) -> Vec < u8 > {
196
+ let mut quoted = b"'" . to_vec ( ) ;
197
+
198
+ while let Some ( pos) = value. find_byte ( b'\'' ) {
199
+ quoted. copy_from_slice ( & value[ ..pos] ) ;
200
+ quoted. copy_from_slice ( b"'\\ ''" ) ;
201
+ value = & value[ pos + 1 ..] ;
202
+ }
203
+
204
+ quoted. copy_from_slice ( value) ;
205
+ quoted. push ( b'\'' ) ;
206
+ quoted
207
+ }
208
+
194
209
impl client:: Transport for SpawnProcessOnDemand {
195
210
fn handshake < ' a > (
196
211
& mut self ,
@@ -216,7 +231,8 @@ impl client::Transport for SpawnProcessOnDemand {
216
231
if self . ssh_cmd . is_some ( ) {
217
232
cmd. args . push ( service. as_str ( ) . into ( ) ) ;
218
233
}
219
- cmd. args . push ( self . path . to_os_str_lossy ( ) . into_owned ( ) ) ;
234
+ cmd. args
235
+ . push ( to_single_quoted ( self . path . as_ref ( ) ) . to_os_str_lossy ( ) . into_owned ( ) ) ;
220
236
221
237
let mut cmd = std:: process:: Command :: from ( cmd) ;
222
238
for env_to_remove in ENV_VARS_TO_REMOVE {
@@ -282,5 +298,18 @@ mod tests {
282
298
}
283
299
}
284
300
}
301
+
302
+ mod handshake {
303
+ use crate :: client:: file:: to_single_quoted;
304
+
305
+ #[ test]
306
+ fn quoted_strings ( ) {
307
+ assert_eq ! ( to_single_quoted( b"my cool string" ) , b"'my cool string'" ) ;
308
+ assert_eq ! (
309
+ to_single_quoted( b"\0 my `even` ~cooler~ $t\\ 'ring\\ // with \" quotes\" " ) ,
310
+ b"'\0 my `even` ~cooler~ $t\\ '\\ ''ring\\ // with \" quotes\" '"
311
+ ) ;
312
+ }
313
+ }
285
314
}
286
315
}
0 commit comments