@@ -627,33 +627,50 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
627627/// to any pre-opened file descriptor.
628628fn open_parent ( p : & Path ) -> io:: Result < ( ManuallyDrop < WasiFd > , PathBuf ) > {
629629 let p = CString :: new ( p. as_os_str ( ) . as_bytes ( ) ) ?;
630- unsafe {
631- let mut ret = ptr:: null ( ) ;
632- let fd = __wasilibc_find_relpath ( p. as_ptr ( ) , & mut ret) ;
633- if fd == -1 {
634- let msg = format ! (
635- "failed to find a pre-opened file descriptor \
636- through which {:?} could be opened",
637- p
630+ let mut buf = Vec :: < u8 > :: with_capacity ( 512 ) ;
631+ loop {
632+ unsafe {
633+ let mut relative_path = buf. as_ptr ( ) . cast ( ) ;
634+ let mut abs_prefix = ptr:: null ( ) ;
635+ let fd = __wasilibc_find_relpath (
636+ p. as_ptr ( ) ,
637+ & mut abs_prefix,
638+ & mut relative_path,
639+ buf. capacity ( ) ,
638640 ) ;
639- return Err ( io:: Error :: new ( io:: ErrorKind :: Other , msg) ) ;
641+ if fd == -1 {
642+ if io:: Error :: last_os_error ( ) . raw_os_error ( ) == Some ( libc:: ENOMEM ) {
643+ // Trigger the internal buffer resizing logic of `Vec` by requiring
644+ // more space than the current capacity.
645+ let cap = buf. capacity ( ) ;
646+ buf. set_len ( cap) ;
647+ buf. reserve ( 1 ) ;
648+ continue ;
649+ }
650+ let msg = format ! (
651+ "failed to find a pre-opened file descriptor \
652+ through which {:?} could be opened",
653+ p
654+ ) ;
655+ return Err ( io:: Error :: new ( io:: ErrorKind :: Other , msg) ) ;
656+ }
657+ let len = CStr :: from_ptr ( buf. as_ptr ( ) . cast ( ) ) . to_bytes ( ) . len ( ) ;
658+ buf. set_len ( len) ;
659+ buf. shrink_to_fit ( ) ;
660+
661+ return Ok ( (
662+ ManuallyDrop :: new ( WasiFd :: from_raw ( fd as u32 ) ) ,
663+ PathBuf :: from ( OsString :: from_vec ( buf) ) ,
664+ ) ) ;
640665 }
641- let path = Path :: new ( OsStr :: from_bytes ( CStr :: from_ptr ( ret) . to_bytes ( ) ) ) ;
642-
643- // FIXME: right now `path` is a pointer into `p`, the `CString` above.
644- // When we return `p` is deallocated and we can't use it, so we need to
645- // currently separately allocate `path`. If this becomes an issue though
646- // we should probably turn this into a closure-taking interface or take
647- // `&CString` and then pass off `&Path` tied to the same lifetime.
648- let path = path. to_path_buf ( ) ;
649-
650- return Ok ( ( ManuallyDrop :: new ( WasiFd :: from_raw ( fd as u32 ) ) , path) ) ;
651666 }
652667
653668 extern "C" {
654669 pub fn __wasilibc_find_relpath (
655670 path : * const libc:: c_char ,
671+ abs_prefix : * mut * const libc:: c_char ,
656672 relative_path : * mut * const libc:: c_char ,
673+ relative_path_len : libc:: size_t ,
657674 ) -> libc:: c_int ;
658675 }
659676}
0 commit comments