char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somruntime: move module graph and bundler into the librarycd262f3

main
2.4 KiB67 linesraw
1use std::io::{self, Read};
2use std::path::{Component, Path};
3
4use crate::authority::SourceAuthority;
5use crate::caps::PathTarget;
6use cap_fs_ext::{DirExt, FollowSymlinks, OpenOptionsFollowExt, OpenOptionsSyncExt};
7
8pub fn open_directory(path: &Path) -> io::Result<cap_std::fs::Dir> {
9    let mut root = std::path::PathBuf::new();
10    let mut names = Vec::new();
11    for component in path.components() {
12        match component {
13            Component::Prefix(_) | Component::RootDir => root.push(component.as_os_str()),
14            Component::Normal(name) => names.push(name),
15            _ => return Err(io::Error::other("Expected a canonical path")),
16        }
17    }
18    let mut directory = cap_std::fs::Dir::open_ambient_dir(root, cap_std::ambient_authority())?;
19    // Canonicalization alone races with symlink replacement. Walk the resolved path
20    // through directory handles without following any newly introduced symlinks.
21    for name in names {
22        directory = directory.open_dir_nofollow(name)?;
23    }
24    Ok(directory)
25}
26
27pub fn read_text(
28    target: &PathTarget,
29    authority: &SourceAuthority,
30) -> Result<String, Box<dyn std::error::Error>> {
31    authority.check_local(target)?;
32    let path = target.as_path();
33    let directory = open_directory(path.parent().ok_or("Expected a module directory")?)?;
34    let mut file = open_file(&directory, target, authority)?;
35    let mut source = String::new();
36    file.read_to_string(&mut source)?;
37    Ok(source)
38}
39
40pub fn open_file(
41    directory: &cap_std::fs::Dir,
42    target: &PathTarget,
43    authority: &SourceAuthority,
44) -> Result<cap_std::fs::File, Box<dyn std::error::Error>> {
45    authority.check_local(target)?;
46    let file_name = target
47        .as_path()
48        .file_name()
49        .ok_or("Expected a module file")?;
50    let file = open_regular(directory, file_name)?;
51    authority.check_local(target)?;
52    Ok(file)
53}
54
55/// Opens a regular file without following symlinks or blocking on special files.
56pub fn open_regular(
57    directory: &cap_std::fs::Dir,
58    file_name: impl AsRef<Path>,
59) -> Result<cap_std::fs::File, Box<dyn std::error::Error>> {
60    let mut options = cap_std::fs::OpenOptions::new();
61    options.read(true).follow(FollowSymlinks::No).nonblock(true);
62    let file = directory.open_with(file_name, &options)?;
63    if !file.metadata()?.is_file() {
64        return Err("Modules must be regular files".into());
65    }
66    Ok(file)
67}