Merge pull request #2538 from deantvv/os-fwalk

os: Add support for fd and dir_fd in `listdir`, `stat`, `fstat`
This commit is contained in:
Noah
2021-04-07 10:41:36 -05:00
committed by GitHub
2 changed files with 43 additions and 22 deletions

View File

@@ -3958,8 +3958,9 @@ class TestScandir(unittest.TestCase):
self.assertIs(type(entry.name), bytes)
self.assertIs(type(entry.path), bytes)
@unittest.skipUnless(os.listdir in os.supports_fd,
'fd support for listdir required for this test.')
# TODO: RUSTPYTHON (scandir needs to have supports_fd)
@unittest.skipUnless(os.scandir in os.supports_fd,
'fd support for scandir required for this test.')
def test_fd(self):
self.assertIn(os.scandir, os.supports_fd)
self.create_file('file.txt')

View File

@@ -159,6 +159,24 @@ impl TryFromObject for PyPathLike {
}
}
fn path_from_fd(raw_fd: i64) -> Result<PathBuf, String> {
cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "macos", windows))] {
let file = rust_file(raw_fd);
let path = match file.path() {
Ok(path) => path,
Err(e) => {
return Err(format!("{:?} Cannot determine path of fd: {:?}", e, raw_fd));
}
};
raw_file_number(file); // Do not consume `raw_fd`
Ok(path)
} else {
Err("fd not supported on wasi yet".to_owned());
}
}
}
fn make_path<'a>(
vm: &VirtualMachine,
path: &'a PyPathLike,
@@ -168,21 +186,14 @@ fn make_path<'a>(
if dir_fd.0.is_none() || path.is_absolute() {
return Ok(path.as_os_str().into());
}
cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "macos", windows))] {
let dir_path = match rust_file(dir_fd.0.unwrap().into()).path() {
Ok(dir_path) => dir_path,
Err(_) => {
return Err(vm.new_os_error(format!("Cannot determine path of dir_fd: {:?}", dir_fd.0)));
}
};
let p: PathBuf = vec![dir_path, path.to_path_buf()].iter().collect();
Ok(p.into_os_string().into())
} else {
return Err(vm.new_os_error("dir_fd not supported on wasi yet".to_owned()));
let dir_path = match path_from_fd(dir_fd.0.unwrap().into()) {
Ok(path) => path,
Err(e) => {
return Err(vm.new_os_error(e));
}
}
};
let p: PathBuf = vec![dir_path, path.to_path_buf()].iter().collect();
Ok(p.into_os_string().into())
}
impl IntoPyException for io::Error {
@@ -555,8 +566,17 @@ mod _os {
}
#[pyfunction]
fn listdir(path: PyPathLike, vm: &VirtualMachine) -> PyResult {
let dir_iter = fs::read_dir(&path.path).map_err(|err| err.into_pyexception(vm))?;
fn listdir(path: Either<PyPathLike, i64>, vm: &VirtualMachine) -> PyResult {
let path = match path {
Either::A(path) => path,
Either::B(fno) => match path_from_fd(fno) {
Ok(path) => PyPathLike::new_str(path.to_string_lossy().to_string()),
Err(e) => {
return Err(vm.new_os_error(e));
}
},
};
let dir_iter = fs::read_dir(&path).map_err(|err| err.into_pyexception(vm))?;
let res: PyResult<Vec<PyObjectRef>> = dir_iter
.map(|entry| match entry {
Ok(entry_path) => path.mode.process_path(entry_path.file_name(), vm),
@@ -900,7 +920,7 @@ mod _os {
#[pyfunction]
fn stat(
file: Either<PyPathLike, i64>,
dir_fd: super::DirFd,
dir_fd: DirFd,
follow_symlinks: FollowSymlinks,
vm: &VirtualMachine,
) -> PyResult {
@@ -1248,7 +1268,7 @@ mod _os {
),
SupportFunc::new(vm, "chdir", chdir, Some(false), None, None),
// chflags Some, None Some
SupportFunc::new(vm, "listdir", listdir, Some(false), None, None),
SupportFunc::new(vm, "listdir", listdir, Some(true), None, None),
SupportFunc::new(vm, "mkdir", mkdir, Some(false), Some(false), None),
// mkfifo Some Some None
// mknod Some Some None
@@ -1259,8 +1279,8 @@ mod _os {
SupportFunc::new(vm, "replace", rename, Some(false), Some(false), None), // TODO: Fix replace
SupportFunc::new(vm, "rmdir", rmdir, Some(false), Some(false), None),
SupportFunc::new(vm, "scandir", scandir, Some(false), None, None),
SupportFunc::new(vm, "stat", stat, Some(false), Some(false), Some(false)),
SupportFunc::new(vm, "fstat", stat, Some(false), Some(false), Some(false)),
SupportFunc::new(vm, "stat", stat, Some(true), Some(true), Some(true)),
SupportFunc::new(vm, "fstat", stat, Some(true), Some(true), Some(true)),
SupportFunc::new(vm, "symlink", platform::symlink, None, Some(false), None),
// truncate Some None None
SupportFunc::new(vm, "unlink", remove, Some(false), Some(false), None),