11
11
use io:: prelude:: * ;
12
12
use os:: windows:: prelude:: * ;
13
13
14
+ use env;
14
15
use ffi:: OsString ;
15
16
use fmt;
16
17
use io:: { self , Error , SeekFrom } ;
17
18
use libc:: { self , HANDLE } ;
18
19
use mem;
19
- use path:: { Path , PathBuf } ;
20
+ use path:: { self , Path , PathBuf } ;
20
21
use ptr;
21
22
use slice;
22
23
use sync:: Arc ;
@@ -227,7 +228,7 @@ impl File {
227
228
}
228
229
229
230
pub fn open ( path : & Path , opts : & OpenOptions ) -> io:: Result < File > {
230
- let path = to_utf16 ( path) ;
231
+ let path = try! ( to_system_path ( path) ) ;
231
232
let handle = unsafe {
232
233
libc:: CreateFileW ( path. as_ptr ( ) ,
233
234
opts. get_desired_access ( ) ,
@@ -378,8 +379,76 @@ impl fmt::Debug for File {
378
379
}
379
380
}
380
381
381
- pub fn to_utf16 ( s : & Path ) -> Vec < u16 > {
382
- s. as_os_str ( ) . encode_wide ( ) . chain ( Some ( 0 ) ) . collect ( )
382
+ pub fn to_u16s ( path : & Path ) -> Vec < u16 > {
383
+ path. as_os_str ( ) . encode_wide ( ) . chain ( Some ( 0 ) ) . collect ( )
384
+ }
385
+
386
+ fn to_system_path ( path : & Path ) -> io:: Result < Vec < u16 > > {
387
+ Ok ( to_u16s ( & * try!( to_system_path_impl ( path, 0 ) ) ) )
388
+ }
389
+
390
+ pub fn to_system_path_impl ( path : & Path , recursion : u8 ) -> io:: Result < PathBuf > {
391
+ if recursion > 1 { unreachable ! ( ) ; }
392
+ let recursion = recursion + 1 ;
393
+
394
+ let mut components = path. components ( ) ;
395
+ let maybe_prefix = {
396
+ let mut copy = components. clone ( ) ;
397
+ copy. next ( ) . and_then ( |c| {
398
+ match c {
399
+ path:: Component :: Prefix ( p) => {
400
+ components = copy;
401
+ Some ( p. kind ( ) )
402
+ }
403
+ _ => None ,
404
+ }
405
+ } )
406
+ } ;
407
+ let mut new_path: PathBuf = match maybe_prefix {
408
+ Some ( path:: Prefix :: Verbatim ( ..) )
409
+ | Some ( path:: Prefix :: VerbatimUNC ( ..) )
410
+ | Some ( path:: Prefix :: VerbatimDisk ( ..) )
411
+ | Some ( path:: Prefix :: DeviceNS ( ..) ) => {
412
+ return Ok ( path. into ( ) )
413
+ }
414
+ // unwrap: The function can only fail getting the current directory,
415
+ // but since the working directory is already absolute, it will not
416
+ // need this value again.
417
+ None => to_system_path_impl ( & * try!( env:: current_dir ( ) ) , recursion) . unwrap ( ) ,
418
+ Some ( path:: Prefix :: Disk ( disk) ) => {
419
+ let current_dir = try!( env:: current_dir ( ) ) ;
420
+ // unwrap: Absolute paths always have a prefix.
421
+ let current_drive = match current_dir. prefix ( ) . unwrap ( ) {
422
+ path:: Prefix :: VerbatimDisk ( d) | path:: Prefix :: Disk ( d) => Some ( d) ,
423
+ _ => None ,
424
+ } ;
425
+ if !path. has_root ( ) && current_drive == Some ( disk) {
426
+ // unwrap: See above.
427
+ to_system_path_impl ( & current_dir, recursion) . unwrap ( )
428
+ } else {
429
+ format ! ( r"\\?\{}:\" , disk as char ) . into ( )
430
+ }
431
+ }
432
+ Some ( path:: Prefix :: UNC ( server, share) ) => {
433
+ let mut new_path = OsString :: new ( ) ;
434
+ new_path. push ( r"\\?\UNC\" ) ;
435
+ new_path. push ( server) ;
436
+ new_path. push ( r"\" ) ;
437
+ new_path. push ( share) ;
438
+ new_path. push ( r"\" ) ;
439
+ new_path. into ( )
440
+ }
441
+ } ;
442
+ for c in components {
443
+ use path:: Component :: * ;
444
+ match c {
445
+ Prefix ( ..) => unreachable ! ( ) ,
446
+ CurDir => { } ,
447
+ ParentDir => { let _ = new_path. pop ( ) ; }
448
+ RootDir | Normal ( ..) => new_path. push ( c. as_os_str ( ) ) ,
449
+ }
450
+ }
451
+ Ok ( new_path)
383
452
}
384
453
385
454
impl FileAttr {
@@ -450,7 +519,7 @@ impl DirBuilder {
450
519
pub fn new ( ) -> DirBuilder { DirBuilder }
451
520
452
521
pub fn mkdir ( & self , p : & Path ) -> io:: Result < ( ) > {
453
- let p = to_utf16 ( p ) ;
522
+ let p = try! ( to_system_path ( p ) ) ;
454
523
try!( cvt ( unsafe {
455
524
libc:: CreateDirectoryW ( p. as_ptr ( ) , ptr:: null_mut ( ) )
456
525
} ) ) ;
@@ -461,7 +530,7 @@ impl DirBuilder {
461
530
pub fn readdir ( p : & Path ) -> io:: Result < ReadDir > {
462
531
let root = p. to_path_buf ( ) ;
463
532
let star = p. join ( "*" ) ;
464
- let path = to_utf16 ( & star) ;
533
+ let path = try! ( to_system_path ( & star) ) ;
465
534
466
535
unsafe {
467
536
let mut wfd = mem:: zeroed ( ) ;
@@ -479,14 +548,14 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
479
548
}
480
549
481
550
pub fn unlink ( p : & Path ) -> io:: Result < ( ) > {
482
- let p_utf16 = to_utf16 ( p ) ;
551
+ let p_utf16 = try! ( to_system_path ( p ) ) ;
483
552
try!( cvt ( unsafe { libc:: DeleteFileW ( p_utf16. as_ptr ( ) ) } ) ) ;
484
553
Ok ( ( ) )
485
554
}
486
555
487
556
pub fn rename ( old : & Path , new : & Path ) -> io:: Result < ( ) > {
488
- let old = to_utf16 ( old) ;
489
- let new = to_utf16 ( new) ;
557
+ let old = try! ( to_system_path ( old) ) ;
558
+ let new = try! ( to_system_path ( new) ) ;
490
559
try!( cvt ( unsafe {
491
560
libc:: MoveFileExW ( old. as_ptr ( ) , new. as_ptr ( ) ,
492
561
libc:: MOVEFILE_REPLACE_EXISTING )
@@ -495,7 +564,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
495
564
}
496
565
497
566
pub fn rmdir ( p : & Path ) -> io:: Result < ( ) > {
498
- let p = to_utf16 ( p ) ;
567
+ let p = try! ( to_system_path ( p ) ) ;
499
568
try!( cvt ( unsafe { c:: RemoveDirectoryW ( p. as_ptr ( ) ) } ) ) ;
500
569
Ok ( ( ) )
501
570
}
@@ -510,8 +579,8 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
510
579
}
511
580
512
581
pub fn symlink_inner ( src : & Path , dst : & Path , dir : bool ) -> io:: Result < ( ) > {
513
- let src = to_utf16 ( src) ;
514
- let dst = to_utf16 ( dst) ;
582
+ let src = try! ( to_system_path ( src) ) ;
583
+ let dst = try! ( to_system_path ( dst) ) ;
515
584
let flags = if dir { c:: SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 } ;
516
585
try!( cvt ( unsafe {
517
586
c:: CreateSymbolicLinkW ( dst. as_ptr ( ) , src. as_ptr ( ) , flags) as libc:: BOOL
@@ -520,8 +589,8 @@ pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> {
520
589
}
521
590
522
591
pub fn link ( src : & Path , dst : & Path ) -> io:: Result < ( ) > {
523
- let src = to_utf16 ( src) ;
524
- let dst = to_utf16 ( dst) ;
592
+ let src = try! ( to_system_path ( src) ) ;
593
+ let dst = try! ( to_system_path ( dst) ) ;
525
594
try!( cvt ( unsafe {
526
595
libc:: CreateHardLinkW ( dst. as_ptr ( ) , src. as_ptr ( ) , ptr:: null_mut ( ) )
527
596
} ) ) ;
@@ -547,7 +616,7 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> {
547
616
}
548
617
549
618
pub fn lstat ( p : & Path ) -> io:: Result < FileAttr > {
550
- let utf16 = to_utf16 ( p ) ;
619
+ let utf16 = try! ( to_system_path ( p ) ) ;
551
620
unsafe {
552
621
let mut attr: FileAttr = mem:: zeroed ( ) ;
553
622
try!( cvt ( c:: GetFileAttributesExW ( utf16. as_ptr ( ) ,
@@ -564,7 +633,7 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
564
633
}
565
634
566
635
pub fn set_perm ( p : & Path , perm : FilePermissions ) -> io:: Result < ( ) > {
567
- let p = to_utf16 ( p ) ;
636
+ let p = try! ( to_system_path ( p ) ) ;
568
637
unsafe {
569
638
try!( cvt ( c:: SetFileAttributesW ( p. as_ptr ( ) , perm. attrs ) ) ) ;
570
639
Ok ( ( ) )
@@ -602,8 +671,8 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
602
671
* ( lpData as * mut i64 ) = TotalBytesTransferred ;
603
672
c:: PROGRESS_CONTINUE
604
673
}
605
- let pfrom = to_utf16 ( from) ;
606
- let pto = to_utf16 ( to ) ;
674
+ let pfrom = try! ( to_system_path ( from) ) ;
675
+ let pto = try! ( to_system_path ( to ) ) ;
607
676
let mut size = 0i64 ;
608
677
try!( cvt ( unsafe {
609
678
c:: CopyFileExW ( pfrom. as_ptr ( ) , pto. as_ptr ( ) , Some ( callback) ,
0 commit comments