@@ -440,3 +440,112 @@ fn fail(s: &str) -> ! {
440440 println ! ( "\n \n {}\n \n " , s) ;
441441 std:: process:: exit ( 1 ) ;
442442}
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