@@ -144,7 +144,7 @@ pub fn do_add_to_path() -> Result<()> {
144
144
_apply_new_path ( new_path)
145
145
}
146
146
147
- fn _apply_new_path ( new_path : Option < String > ) -> Result < ( ) > {
147
+ fn _apply_new_path ( new_path : Option < Vec < u16 > > ) -> Result < ( ) > {
148
148
use std:: ptr;
149
149
use winapi:: shared:: minwindef:: * ;
150
150
use winapi:: um:: winuser:: {
@@ -169,7 +169,7 @@ fn _apply_new_path(new_path: Option<String>) -> Result<()> {
169
169
. chain_err ( || ErrorKind :: PermissionDenied ) ?;
170
170
} else {
171
171
let reg_value = RegValue {
172
- bytes : utils:: string_to_winreg_bytes ( & new_path) ,
172
+ bytes : utils:: string_to_winreg_bytes ( new_path) ,
173
173
vtype : RegType :: REG_EXPAND_SZ ,
174
174
} ;
175
175
environment
@@ -194,9 +194,9 @@ fn _apply_new_path(new_path: Option<String>) -> Result<()> {
194
194
}
195
195
196
196
// Get the windows PATH variable out of the registry as a String. If
197
- // this returns None then the PATH variable is not unicode and we
197
+ // this returns None then the PATH variable is not a string and we
198
198
// should not mess with it.
199
- fn get_windows_path_var ( ) -> Result < Option < String > > {
199
+ fn get_windows_path_var ( ) -> Result < Option < Vec < u16 > > > {
200
200
use std:: io;
201
201
use winreg:: enums:: { HKEY_CURRENT_USER , KEY_READ , KEY_WRITE } ;
202
202
use winreg:: RegKey ;
@@ -212,63 +212,72 @@ fn get_windows_path_var() -> Result<Option<String>> {
212
212
if let Some ( s) = utils:: string_from_winreg_value ( & val) {
213
213
Ok ( Some ( s) )
214
214
} else {
215
- warn ! ( "the registry key HKEY_CURRENT_USER\\ Environment\\ PATH does not contain valid Unicode. \
216
- Not modifying the PATH variable") ;
215
+ warn ! (
216
+ "the registry key HKEY_CURRENT_USER\\ Environment\\ PATH is not a string. \
217
+ Not modifying the PATH variable"
218
+ ) ;
217
219
Ok ( None )
218
220
}
219
221
}
220
- Err ( ref e) if e. kind ( ) == io:: ErrorKind :: NotFound => Ok ( Some ( String :: new ( ) ) ) ,
222
+ Err ( ref e) if e. kind ( ) == io:: ErrorKind :: NotFound => Ok ( Some ( Vec :: new ( ) ) ) ,
221
223
Err ( e) => Err ( e) . chain_err ( || ErrorKind :: WindowsUninstallMadness ) ,
222
224
}
223
225
}
224
226
225
227
// Returns None if the existing old_path does not need changing, otherwise
226
228
// prepends the path_str to old_path, handling empty old_path appropriately.
227
- fn _add_to_path ( old_path : & str , path_str : String ) -> Option < String > {
229
+ fn _add_to_path ( old_path : Vec < u16 > , path_str : Vec < u16 > ) -> Option < Vec < u16 > > {
228
230
if old_path. is_empty ( ) {
229
231
Some ( path_str)
230
- } else if old_path. contains ( & path_str) {
232
+ } else if old_path
233
+ . windows ( path_str. len ( ) )
234
+ . any ( |path| path == path_str)
235
+ {
231
236
None
232
237
} else {
233
238
let mut new_path = path_str;
234
- new_path. push_str ( ";" ) ;
235
- new_path. push_str ( & old_path) ;
239
+ new_path. push ( b';' as u16 ) ;
240
+ new_path. extend_from_slice ( & old_path) ;
236
241
Some ( new_path)
237
242
}
238
243
}
239
244
240
245
// Returns None if the existing old_path does not need changing
241
- fn _remove_from_path ( old_path : & str , path_str : String ) -> Option < String > {
242
- let idx = old_path. find ( & path_str) ?;
246
+ fn _remove_from_path ( old_path : Vec < u16 > , path_str : Vec < u16 > ) -> Option < Vec < u16 > > {
247
+ let idx = old_path
248
+ . windows ( path_str. len ( ) )
249
+ . position ( |path| path == path_str) ?;
243
250
// If there's a trailing semicolon (likely, since we probably added one
244
251
// during install), include that in the substring to remove. We don't search
245
252
// for that to find the string, because if its the last string in the path,
246
253
// there may not be.
247
254
let mut len = path_str. len ( ) ;
248
- if old_path. as_bytes ( ) . get ( idx + path_str. len ( ) ) == Some ( & b';' ) {
255
+ if old_path. get ( idx + path_str. len ( ) ) == Some ( & ( b';' as u16 ) ) {
249
256
len += 1 ;
250
257
}
251
258
252
- let mut new_path = old_path[ ..idx] . to_string ( ) ;
253
- new_path. push_str ( & old_path[ idx + len..] ) ;
259
+ let mut new_path = old_path[ ..idx] . to_owned ( ) ;
260
+ new_path. extend_from_slice ( & old_path[ idx + len..] ) ;
254
261
// Don't leave a trailing ; though, we don't want an empty string in the
255
262
// path.
256
- if new_path. ends_with ( ';' ) {
263
+ if new_path. last ( ) == Some ( & ( b ';' as u16 ) ) {
257
264
new_path. pop ( ) ;
258
265
}
259
266
Some ( new_path)
260
267
}
261
268
262
- fn _with_path_cargo_home_bin < F > ( f : F ) -> Result < Option < String > >
269
+ fn _with_path_cargo_home_bin < F > ( f : F ) -> Result < Option < Vec < u16 > > >
263
270
where
264
- F : FnOnce ( & str , String ) -> Option < String > ,
271
+ F : FnOnce ( Vec < u16 > , Vec < u16 > ) -> Option < Vec < u16 > > ,
265
272
{
273
+ use std:: ffi:: OsString ;
274
+ use std:: os:: windows:: ffi:: OsStrExt ;
275
+
266
276
let windows_path = get_windows_path_var ( ) ?;
267
- let path_str = utils:: cargo_home ( ) ?
268
- . join ( "bin" )
269
- . to_string_lossy ( )
270
- . into_owned ( ) ;
271
- Ok ( windows_path. and_then ( |old_path| f ( & old_path, path_str) ) )
277
+ let mut path_str = utils:: cargo_home ( ) ?;
278
+ path_str. push ( "bin" ) ;
279
+ Ok ( windows_path
280
+ . and_then ( |old_path| f ( old_path, OsString :: from ( path_str) . encode_wide ( ) . collect ( ) ) ) )
272
281
}
273
282
274
283
pub fn do_remove_from_path ( ) -> Result < ( ) > {
@@ -402,26 +411,33 @@ pub fn delete_rustup_and_cargo_home() -> Result<()> {
402
411
403
412
#[ cfg( test) ]
404
413
mod tests {
414
+ use std:: ffi:: OsString ;
415
+ use std:: os:: windows:: ffi:: OsStrExt ;
416
+
405
417
use winreg:: enums:: { RegType , HKEY_CURRENT_USER , KEY_READ , KEY_WRITE } ;
406
418
use winreg:: { RegKey , RegValue } ;
407
419
408
420
use crate :: currentprocess;
409
421
use crate :: test:: with_saved_path;
410
422
use crate :: utils:: utils;
411
423
424
+ fn wide ( str : & str ) -> Vec < u16 > {
425
+ OsString :: from ( str) . encode_wide ( ) . collect ( )
426
+ }
427
+
412
428
#[ test]
413
429
fn windows_install_does_not_add_path_twice ( ) {
414
430
assert_eq ! (
415
431
None ,
416
432
super :: _add_to_path(
417
- r"c:\users\example\.cargo\bin;foo" ,
418
- r"c:\users\example\.cargo\bin" . into ( )
433
+ wide ( r"c:\users\example\.cargo\bin;foo" ) ,
434
+ wide ( r"c:\users\example\.cargo\bin" )
419
435
)
420
436
) ;
421
437
}
422
438
423
439
#[ test]
424
- fn windows_doesnt_mess_with_a_non_unicode_path ( ) {
440
+ fn windows_doesnt_mess_with_a_non_string_path ( ) {
425
441
// This writes an error, so we want a sink for it.
426
442
let tp = Box :: new ( currentprocess:: TestProcess {
427
443
vars : [ ( "HOME" . to_string ( ) , "/unused" . to_string ( ) ) ]
@@ -437,23 +453,19 @@ mod tests {
437
453
. open_subkey_with_flags ( "Environment" , KEY_READ | KEY_WRITE )
438
454
. unwrap ( ) ;
439
455
let reg_value = RegValue {
440
- bytes : vec ! [
441
- 0x00 , 0xD8 , // leading surrogate
442
- 0x01 , 0x01 , // bogus trailing surrogate
443
- 0x00 , 0x00 ,
444
- ] , // null
445
- vtype : RegType :: REG_EXPAND_SZ ,
456
+ bytes : vec ! [ 0x00 , 0xD8 , 0x01 , 0x01 , 0x00 , 0x00 ] ,
457
+ vtype : RegType :: REG_BINARY ,
446
458
} ;
447
459
environment. set_raw_value ( "PATH" , & reg_value) . unwrap ( ) ;
448
460
// Ok(None) signals no change to the PATH setting layer
449
- fn panic ( _ : & str , _ : String ) -> Option < String > {
450
- panic ! ( "called" ) ;
451
- }
452
- assert_eq ! ( None , super :: _with_path_cargo_home_bin ( panic ) . unwrap ( ) ) ;
461
+ assert_eq ! (
462
+ None ,
463
+ super :: _with_path_cargo_home_bin ( |_ , _| panic! ( "called" ) ) . unwrap ( )
464
+ ) ;
453
465
} )
454
466
} ) ;
455
467
assert_eq ! (
456
- r"warning: the registry key HKEY_CURRENT_USER\Environment\PATH does not contain valid Unicode . Not modifying the PATH variable
468
+ r"warning: the registry key HKEY_CURRENT_USER\Environment\PATH is not a string . Not modifying the PATH variable
457
469
" ,
458
470
String :: from_utf8( tp. get_stderr( ) ) . unwrap( )
459
471
) ;
@@ -474,15 +486,15 @@ mod tests {
474
486
{
475
487
// Can't compare the Results as Eq isn't derived; thanks error-chain.
476
488
#![ allow( clippy:: unit_cmp) ]
477
- assert_eq ! ( ( ) , super :: _apply_new_path( Some ( "foo" . into ( ) ) ) . unwrap( ) ) ;
489
+ assert_eq ! ( ( ) , super :: _apply_new_path( Some ( wide ( "foo" ) ) ) . unwrap( ) ) ;
478
490
}
479
491
let root = RegKey :: predef ( HKEY_CURRENT_USER ) ;
480
492
let environment = root
481
493
. open_subkey_with_flags ( "Environment" , KEY_READ | KEY_WRITE )
482
494
. unwrap ( ) ;
483
495
let path = environment. get_raw_value ( "PATH" ) . unwrap ( ) ;
484
496
assert_eq ! ( path. vtype, RegType :: REG_EXPAND_SZ ) ;
485
- assert_eq ! ( utils:: string_to_winreg_bytes( "foo" ) , & path. bytes[ ..] ) ;
497
+ assert_eq ! ( utils:: string_to_winreg_bytes( wide ( "foo" ) ) , & path. bytes[ ..] ) ;
486
498
} )
487
499
} ) ;
488
500
}
@@ -503,7 +515,7 @@ mod tests {
503
515
. set_raw_value (
504
516
"PATH" ,
505
517
& RegValue {
506
- bytes : utils:: string_to_winreg_bytes ( "foo" ) ,
518
+ bytes : utils:: string_to_winreg_bytes ( wide ( "foo" ) ) ,
507
519
vtype : RegType :: REG_EXPAND_SZ ,
508
520
} ,
509
521
)
@@ -512,7 +524,7 @@ mod tests {
512
524
{
513
525
// Can't compare the Results as Eq isn't derived; thanks error-chain.
514
526
#![ allow( clippy:: unit_cmp) ]
515
- assert_eq ! ( ( ) , super :: _apply_new_path( Some ( "" . into ( ) ) ) . unwrap( ) ) ;
527
+ assert_eq ! ( ( ) , super :: _apply_new_path( Some ( Vec :: new ( ) ) ) . unwrap( ) ) ;
516
528
}
517
529
let reg_value = environment. get_raw_value ( "PATH" ) ;
518
530
match reg_value {
@@ -536,18 +548,18 @@ mod tests {
536
548
. unwrap ( ) ;
537
549
environment. delete_value ( "PATH" ) . unwrap ( ) ;
538
550
539
- assert_eq ! ( Some ( "" . into ( ) ) , super :: get_windows_path_var( ) . unwrap( ) ) ;
551
+ assert_eq ! ( Some ( Vec :: new ( ) ) , super :: get_windows_path_var( ) . unwrap( ) ) ;
540
552
} )
541
553
} ) ;
542
554
}
543
555
544
556
#[ test]
545
557
fn windows_uninstall_removes_semicolon_from_path_prefix ( ) {
546
558
assert_eq ! (
547
- "foo" ,
559
+ wide ( "foo" ) ,
548
560
super :: _remove_from_path(
549
- r"c:\users\example\.cargo\bin;foo" ,
550
- r"c:\users\example\.cargo\bin" . into ( )
561
+ wide ( r"c:\users\example\.cargo\bin;foo" ) ,
562
+ wide ( r"c:\users\example\.cargo\bin" ) ,
551
563
)
552
564
. unwrap( )
553
565
)
@@ -556,10 +568,10 @@ mod tests {
556
568
#[ test]
557
569
fn windows_uninstall_removes_semicolon_from_path_suffix ( ) {
558
570
assert_eq ! (
559
- "foo" ,
571
+ wide ( "foo" ) ,
560
572
super :: _remove_from_path(
561
- r"foo;c:\users\example\.cargo\bin" ,
562
- r"c:\users\example\.cargo\bin" . into ( )
573
+ wide ( r"foo;c:\users\example\.cargo\bin" ) ,
574
+ wide ( r"c:\users\example\.cargo\bin" ) ,
563
575
)
564
576
. unwrap( )
565
577
)
0 commit comments