@@ -440,3 +440,112 @@ fn fail(s: &str) -> ! {
440
440
println ! ( "\n \n {}\n \n " , s) ;
441
441
std:: process:: exit ( 1 ) ;
442
442
}
443
+
444
+ /// Copied from `std::path::absolute` until it stabilizes.
445
+ ///
446
+ /// FIXME: this shouldn't exist.
447
+ pub ( crate ) fn absolute ( path : & Path ) -> PathBuf {
448
+ if path. as_os_str ( ) . is_empty ( ) {
449
+ panic ! ( "can't make empty path absolute" ) ;
450
+ }
451
+ #[ cfg( unix) ]
452
+ {
453
+ t ! ( absolute_unix( path) , format!( "could not make path absolute: {}" , path. display( ) ) )
454
+ }
455
+ #[ cfg( windows) ]
456
+ {
457
+ t ! ( absolute_windows( path) , format!( "could not make path absolute: {}" , path. display( ) ) )
458
+ }
459
+ #[ cfg( not( any( unix, windows) ) ) ]
460
+ {
461
+ println ! ( "warning: bootstrap is not supported on non-unix platforms" ) ;
462
+ t ! ( std:: fs:: canonicalize( t!( std:: env:: current_dir( ) ) ) ) . join ( path)
463
+ }
464
+ }
465
+
466
+ #[ cfg( unix) ]
467
+ /// Make a POSIX path absolute without changing its semantics.
468
+ fn absolute_unix ( path : & Path ) -> io:: Result < PathBuf > {
469
+ // This is mostly a wrapper around collecting `Path::components`, with
470
+ // exceptions made where this conflicts with the POSIX specification.
471
+ // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
472
+ // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
473
+
474
+ use std:: os:: unix:: prelude:: OsStrExt ;
475
+ let mut components = path. components ( ) ;
476
+ let path_os = path. as_os_str ( ) . as_bytes ( ) ;
477
+
478
+ let mut normalized = if path. is_absolute ( ) {
479
+ // "If a pathname begins with two successive <slash> characters, the
480
+ // first component following the leading <slash> characters may be
481
+ // interpreted in an implementation-defined manner, although more than
482
+ // two leading <slash> characters shall be treated as a single <slash>
483
+ // character."
484
+ if path_os. starts_with ( b"//" ) && !path_os. starts_with ( b"///" ) {
485
+ components. next ( ) ;
486
+ PathBuf :: from ( "//" )
487
+ } else {
488
+ PathBuf :: new ( )
489
+ }
490
+ } else {
491
+ env:: current_dir ( ) ?
492
+ } ;
493
+ normalized. extend ( components) ;
494
+
495
+ // "Interfaces using pathname resolution may specify additional constraints
496
+ // when a pathname that does not name an existing directory contains at
497
+ // least one non- <slash> character and contains one or more trailing
498
+ // <slash> characters".
499
+ // A trailing <slash> is also meaningful if "a symbolic link is
500
+ // encountered during pathname resolution".
501
+
502
+ if path_os. ends_with ( b"/" ) {
503
+ normalized. push ( "" ) ;
504
+ }
505
+
506
+ Ok ( normalized)
507
+ }
508
+
509
+ #[ cfg( windows) ]
510
+ fn absolute_windows ( path : & std:: path:: Path ) -> std:: io:: Result < std:: path:: PathBuf > {
511
+ use std:: ffi:: OsString ;
512
+ use std:: io:: Error ;
513
+ use std:: os:: windows:: ffi:: { OsStrExt , OsStringExt } ;
514
+ use std:: ptr:: null_mut;
515
+ #[ link( name = "kernel32" ) ]
516
+ extern "system" {
517
+ fn GetFullPathNameW (
518
+ lpFileName : * const u16 ,
519
+ nBufferLength : u32 ,
520
+ lpBuffer : * mut u16 ,
521
+ lpFilePart : * mut * const u16 ,
522
+ ) -> u32 ;
523
+ }
524
+
525
+ unsafe {
526
+ // encode the path as UTF-16
527
+ let path: Vec < u16 > = path. as_os_str ( ) . encode_wide ( ) . chain ( [ 0 ] ) . collect ( ) ;
528
+ let mut buffer = Vec :: new ( ) ;
529
+ // Loop until either success or failure.
530
+ loop {
531
+ // Try to get the absolute path
532
+ let len = GetFullPathNameW (
533
+ path. as_ptr ( ) ,
534
+ buffer. len ( ) . try_into ( ) . unwrap ( ) ,
535
+ buffer. as_mut_ptr ( ) ,
536
+ null_mut ( ) ,
537
+ ) ;
538
+ match len as usize {
539
+ // Failure
540
+ 0 => return Err ( Error :: last_os_error ( ) ) ,
541
+ // Buffer is too small, resize.
542
+ len if len > buffer. len ( ) => buffer. resize ( len, 0 ) ,
543
+ // Success!
544
+ len => {
545
+ buffer. truncate ( len) ;
546
+ return Ok ( OsString :: from_wide ( & buffer) . into ( ) ) ;
547
+ }
548
+ }
549
+ }
550
+ }
551
+ }
0 commit comments