Skip to content

Commit bd3ca77

Browse files
committed
WASI implementation of NativePath
1 parent 64ff8e2 commit bd3ca77

File tree

2 files changed

+113
-60
lines changed

2 files changed

+113
-60
lines changed

library/std/src/os/wasi/fs.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,9 @@ pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
563563
/// This is a convenience API similar to `std::os::unix::fs::symlink` and
564564
/// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`.
565565
pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> io::Result<()> {
566-
crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref())
566+
crate::sys::common::small_c_string::run_path_with_cstr(new_path.as_ref(), &|new_path| {
567+
crate::sys::fs::symlink(old_path.as_ref(), new_path)
568+
})
567569
}
568570

569571
fn osstr2str(f: &OsStr) -> io::Result<&str> {

library/std/src/sys/pal/wasi/fs.rs

+110-59
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,58 @@ use crate::sys::time::SystemTime;
1717
use crate::sys::unsupported;
1818
use crate::sys_common::{AsInner, FromInner, IntoInner};
1919

20-
pub use crate::sys_common::fs::try_exists;
20+
pub(crate) mod fs_imp {
21+
pub(crate) use super::{
22+
DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
23+
ReadDir,
24+
};
25+
use crate::io;
26+
use crate::path::AsPath;
27+
use crate::path::PathBuf;
28+
29+
pub(crate) fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
30+
path.with_native_path(super::unlink)
31+
}
32+
pub(crate) fn symlink_metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
33+
path.with_native_path(|path| super::lstat(path))
34+
}
35+
pub(crate) fn metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
36+
path.with_native_path(|path| super::stat(path))
37+
}
38+
pub(crate) fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
39+
to.with_path(|to| from.with_native_path(|from| super::rename(from, to)))
40+
}
41+
pub(crate) fn hard_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
42+
link.with_path(|link| original.with_native_path(|original| super::link(original, link)))
43+
}
44+
pub(crate) fn soft_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
45+
original.with_path(|original| link.with_native_path(|link| super::symlink(original, link)))
46+
}
47+
pub(crate) fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
48+
path.with_native_path(super::rmdir)
49+
}
50+
pub(crate) fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
51+
path.with_path(super::readdir)
52+
}
53+
pub(crate) fn set_permissions<P: AsPath>(path: P, perms: FilePermissions) -> io::Result<()> {
54+
path.with_path(|path| super::set_perm(path, perms))
55+
}
56+
pub(crate) fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
57+
from.with_path(|from| to.with_path(|to| super::copy(from, to)))
58+
}
59+
pub(crate) fn canonicalize<P: AsPath>(path: P) -> io::Result<PathBuf> {
60+
path.with_path(super::canonicalize)
61+
}
62+
pub(crate) fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
63+
path.with_path(super::remove_dir_all)
64+
}
65+
pub(crate) fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
66+
path.with_native_path(super::readlink)
67+
}
68+
pub(crate) fn try_exists<P: AsPath>(path: P) -> io::Result<bool> {
69+
path.with_path(crate::sys_common::fs::try_exists)
70+
}
71+
}
2172

2273
pub struct File {
2374
fd: WasiFd,
@@ -398,7 +449,7 @@ impl OpenOptions {
398449
}
399450

400451
impl File {
401-
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
452+
pub fn open_native(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
402453
let (dir, file) = open_parent(path)?;
403454
open_at(&dir, &file, opts)
404455
}
@@ -548,8 +599,10 @@ impl DirBuilder {
548599
}
549600

550601
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
551-
let (dir, file) = open_parent(p)?;
552-
dir.create_directory(osstr2str(file.as_ref())?)
602+
run_path_with_cstr(p, &|p| {
603+
let (dir, file) = open_parent(p)?;
604+
dir.create_directory(osstr2str(file.as_ref())?)
605+
})
553606
}
554607
}
555608

@@ -563,18 +616,18 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
563616
let mut opts = OpenOptions::new();
564617
opts.directory(true);
565618
opts.read(true);
566-
let dir = File::open(p, &opts)?;
619+
let dir = run_path_with_cstr(p, &|p| File::open_native(p, &opts))?;
567620
Ok(ReadDir::new(dir, p.to_path_buf()))
568621
}
569622

570-
pub fn unlink(p: &Path) -> io::Result<()> {
623+
pub fn unlink(p: &CStr) -> io::Result<()> {
571624
let (dir, file) = open_parent(p)?;
572625
dir.unlink_file(osstr2str(file.as_ref())?)
573626
}
574627

575-
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
628+
pub fn rename(old: &CStr, new: &Path) -> io::Result<()> {
576629
let (old, old_file) = open_parent(old)?;
577-
let (new, new_file) = open_parent(new)?;
630+
let (new, new_file) = run_path_with_cstr(new, &|new| open_parent(new))?;
578631
old.rename(osstr2str(old_file.as_ref())?, &new, osstr2str(new_file.as_ref())?)
579632
}
580633

@@ -584,12 +637,12 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
584637
unsupported()
585638
}
586639

587-
pub fn rmdir(p: &Path) -> io::Result<()> {
640+
pub fn rmdir(p: &CStr) -> io::Result<()> {
588641
let (dir, file) = open_parent(p)?;
589642
dir.remove_directory(osstr2str(file.as_ref())?)
590643
}
591644

592-
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
645+
pub fn readlink(p: &CStr) -> io::Result<PathBuf> {
593646
let (dir, file) = open_parent(p)?;
594647
read_link(&dir, &file)
595648
}
@@ -625,24 +678,24 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
625678
}
626679
}
627680

628-
pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
681+
pub fn symlink(original: &Path, link: &CStr) -> io::Result<()> {
629682
let (link, link_file) = open_parent(link)?;
630683
link.symlink(osstr2str(original.as_ref())?, osstr2str(link_file.as_ref())?)
631684
}
632685

633-
pub fn link(original: &Path, link: &Path) -> io::Result<()> {
686+
pub fn link(original: &CStr, link: &Path) -> io::Result<()> {
634687
let (original, original_file) = open_parent(original)?;
635-
let (link, link_file) = open_parent(link)?;
688+
let (link, link_file) = run_path_with_cstr(link, &|link| open_parent(link))?;
636689
// Pass 0 as the flags argument, meaning don't follow symlinks.
637690
original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?)
638691
}
639692

640-
pub fn stat(p: &Path) -> io::Result<FileAttr> {
693+
pub fn stat(p: &CStr) -> io::Result<FileAttr> {
641694
let (dir, file) = open_parent(p)?;
642695
metadata_at(&dir, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, &file)
643696
}
644697

645-
pub fn lstat(p: &Path) -> io::Result<FileAttr> {
698+
pub fn lstat(p: &CStr) -> io::Result<FileAttr> {
646699
let (dir, file) = open_parent(p)?;
647700
metadata_at(&dir, 0, &file)
648701
}
@@ -697,53 +750,51 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
697750
///
698751
/// Note that this can fail if `p` doesn't look like it can be opened relative
699752
/// to any pre-opened file descriptor.
700-
fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
701-
run_path_with_cstr(p, &|p| {
702-
let mut buf = Vec::<u8>::with_capacity(512);
703-
loop {
704-
unsafe {
705-
let mut relative_path = buf.as_ptr().cast();
706-
let mut abs_prefix = ptr::null();
707-
let fd = __wasilibc_find_relpath(
708-
p.as_ptr(),
709-
&mut abs_prefix,
710-
&mut relative_path,
711-
buf.capacity(),
712-
);
713-
if fd == -1 {
714-
if io::Error::last_os_error().raw_os_error() == Some(libc::ENOMEM) {
715-
// Trigger the internal buffer resizing logic of `Vec` by requiring
716-
// more space than the current capacity.
717-
let cap = buf.capacity();
718-
buf.set_len(cap);
719-
buf.reserve(1);
720-
continue;
721-
}
722-
let msg = format!(
723-
"failed to find a pre-opened file descriptor \
724-
through which {:?} could be opened",
725-
p
726-
);
727-
return Err(io::Error::new(io::ErrorKind::Uncategorized, msg));
753+
fn open_parent(p: &CStr) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
754+
let mut buf = Vec::<u8>::with_capacity(512);
755+
loop {
756+
unsafe {
757+
let mut relative_path = buf.as_ptr().cast();
758+
let mut abs_prefix = ptr::null();
759+
let fd = __wasilibc_find_relpath(
760+
p.as_ptr(),
761+
&mut abs_prefix,
762+
&mut relative_path,
763+
buf.capacity(),
764+
);
765+
if fd == -1 {
766+
if io::Error::last_os_error().raw_os_error() == Some(libc::ENOMEM) {
767+
// Trigger the internal buffer resizing logic of `Vec` by requiring
768+
// more space than the current capacity.
769+
let cap = buf.capacity();
770+
buf.set_len(cap);
771+
buf.reserve(1);
772+
continue;
728773
}
729-
let relative = CStr::from_ptr(relative_path).to_bytes().to_vec();
730-
731-
return Ok((
732-
ManuallyDrop::new(WasiFd::from_raw_fd(fd as c_int)),
733-
PathBuf::from(OsString::from_vec(relative)),
734-
));
774+
let msg = format!(
775+
"failed to find a pre-opened file descriptor \
776+
through which {:?} could be opened",
777+
p
778+
);
779+
return Err(io::Error::new(io::ErrorKind::Uncategorized, msg));
735780
}
736-
}
781+
let relative = CStr::from_ptr(relative_path).to_bytes().to_vec();
737782

738-
extern "C" {
739-
pub fn __wasilibc_find_relpath(
740-
path: *const libc::c_char,
741-
abs_prefix: *mut *const libc::c_char,
742-
relative_path: *mut *const libc::c_char,
743-
relative_path_len: libc::size_t,
744-
) -> libc::c_int;
783+
return Ok((
784+
ManuallyDrop::new(WasiFd::from_raw_fd(fd as c_int)),
785+
PathBuf::from(OsString::from_vec(relative)),
786+
));
745787
}
746-
})
788+
}
789+
790+
extern "C" {
791+
pub fn __wasilibc_find_relpath(
792+
path: *const libc::c_char,
793+
abs_prefix: *mut *const libc::c_char,
794+
relative_path: *mut *const libc::c_char,
795+
relative_path_len: libc::size_t,
796+
) -> libc::c_int;
797+
}
747798
}
748799

749800
pub fn osstr2str(f: &OsStr) -> io::Result<&str> {
@@ -761,7 +812,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
761812
}
762813

763814
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
764-
let (parent, path) = open_parent(path)?;
815+
let (parent, path) = run_path_with_cstr(path, &|path| open_parent(path))?;
765816
remove_dir_all_recursive(&parent, &path)
766817
}
767818

0 commit comments

Comments
 (0)