Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions docs/_docs/user-guide/eldritch.md
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,54 @@ The **file.mkdir** method will make a new directory at `path`. If the parent dir

The **file.move** method moves a file or directory from `src` to `dst`. If the `dst` directory or file exists it will be deleted before being replaced to ensure consistency across systems.

### file.path_abs

Returns an absolute representation of path.

```python
file.path_abs(path: str) -> str
```

### file.path_base

Returns the last element of path.

```python
file.path_base(path: str) -> str
```

### file.path_clean

Returns the shortest path name equivalent to path by purely lexical processing.

```python
file.path_clean(path: str) -> str
```

### file.path_dir

Returns all but the last element of path, typically the path's directory.

```python
file.path_dir(path: str) -> str
```

### file.path_join

Joins two path elements into a single path, separating them with an OS specific separator.

```python
file.path_join(base: str, target: str) -> str
```

### file.path_separator

Returns the operating system-specific path separator.

```python
file.path_separator() -> str
```

### file.parent_dir

`file.parent_dir(path: str) -> str`
Expand Down
31 changes: 31 additions & 0 deletions implants/lib/eldritch/stdlib/eldritch-libfile/src/fake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,37 @@ impl FileLibrary for FileLibraryFake {
Err("Parent path not found".to_string())
}

fn path_abs(&self, path: String) -> Result<String, String> {
if path.is_empty() {
return Ok("/home/user".into());
}
if path.starts_with("/") {
return self.path_clean(path);
}
let joined = alloc::format!("/home/user/{}", path);
self.path_clean(joined)
}

fn path_clean(&self, path: String) -> Result<String, String> {
crate::std::path_clean_impl::path_clean(path)
}

fn path_base(&self, path: String) -> Result<String, String> {
crate::std::path_base_impl::path_base(path)
}

fn path_join(&self, base: String, target: String) -> Result<String, String> {
crate::std::path_join_impl::path_join(base, target)
}

fn path_dir(&self, path: String) -> Result<String, String> {
crate::std::path_dir_impl::path_dir(path)
}

fn path_separator(&self) -> Result<String, String> {
Ok("/".to_string())
}

fn find(
&self,
_path: String,
Expand Down
61 changes: 61 additions & 0 deletions implants/lib/eldritch/stdlib/eldritch-libfile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,67 @@ pub trait FileLibrary {
///
/// **Errors**
/// - Returns an error string if the search encounters issues.
#[eldritch_method]
/// Returns an absolute representation of path.
///
/// **Parameters**
/// - `path` (`str`): The path to convert.
///
/// **Returns**
/// - `str`: The absolute path.
///
/// **Errors**
/// - Returns an error string if the current working directory cannot be determined.
fn path_abs(&self, path: String) -> Result<String, String>;

#[eldritch_method]
/// Returns the shortest path name equivalent to path by purely lexical processing.
///
/// **Parameters**
/// - `path` (`str`): The path to clean.
///
/// **Returns**
/// - `str`: The cleaned path.
fn path_clean(&self, path: String) -> Result<String, String>;

#[eldritch_method]
/// Returns the last element of path.
///
/// **Parameters**
/// - `path` (`str`): The path.
///
/// **Returns**
/// - `str`: The base name of the path.
fn path_base(&self, path: String) -> Result<String, String>;

#[eldritch_method]
/// Joins two path elements into a single path, separating them with an OS specific separator.
///
/// **Parameters**
/// - `base` (`str`): The base path.
/// - `target` (`str`): The target path.
///
/// **Returns**
/// - `str`: The joined path.
fn path_join(&self, base: String, target: String) -> Result<String, String>;

#[eldritch_method]
/// Returns all but the last element of path, typically the path's directory.
///
/// **Parameters**
/// - `path` (`str`): The path.
///
/// **Returns**
/// - `str`: The directory of the path.
fn path_dir(&self, path: String) -> Result<String, String>;

#[eldritch_method]
/// Returns the operating system-specific path separator.
///
/// **Returns**
/// - `str`: The path separator ("/" or "\").
fn path_separator(&self) -> Result<String, String>;

fn find(
&self,
path: String,
Expand Down
30 changes: 30 additions & 0 deletions implants/lib/eldritch/stdlib/eldritch-libfile/src/std/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ pub mod list_recent_impl;
pub mod mkdir_impl;
pub mod move_impl;
pub mod parent_dir_impl;
pub mod path_abs_impl;
pub mod path_base_impl;
pub mod path_clean_impl;
pub mod path_dir_impl;
pub mod path_join_impl;
pub mod path_separator_impl;
pub mod pwd_impl;
pub mod read_binary_impl;
pub mod read_impl;
Expand Down Expand Up @@ -166,6 +172,30 @@ impl FileLibrary for StdFileLibrary {
write_binary_impl::write_binary(path, content)
}

fn path_abs(&self, path: String) -> Result<String, String> {
path_abs_impl::path_abs(path)
}

fn path_clean(&self, path: String) -> Result<String, String> {
path_clean_impl::path_clean(path)
}

fn path_base(&self, path: String) -> Result<String, String> {
path_base_impl::path_base(path)
}

fn path_join(&self, base: String, target: String) -> Result<String, String> {
path_join_impl::path_join(base, target)
}

fn path_dir(&self, path: String) -> Result<String, String> {
path_dir_impl::path_dir(path)
}

fn path_separator(&self) -> Result<String, String> {
path_separator_impl::path_separator()
}

fn find(
&self,
path: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use alloc::string::String;
use alloc::string::ToString;

pub fn path_abs(path: String) -> Result<String, String> {
if path.is_empty() {
return Ok(std::env::current_dir()
.map_err(|e| e.to_string())?
.to_string_lossy()
.into_owned());
}

let p = std::path::Path::new(&path);
if p.is_absolute() {
return super::path_clean_impl::path_clean(path);
}

let cwd = std::env::current_dir().map_err(|e| e.to_string())?;
let joined = cwd.join(p);
super::path_clean_impl::path_clean(joined.to_string_lossy().into_owned())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use alloc::string::String;

pub fn path_base(path: String) -> Result<String, String> {
if path.is_empty() {
return Ok(".".into());
}

let separator = std::path::MAIN_SEPARATOR;
let mut p = path.as_str();
while p.len() > 1 && p.ends_with(separator) {
p = &p[..p.len() - 1];
}

if p == separator.to_string() {
return Ok(separator.to_string());
}

if let Some(idx) = p.rfind(separator) {
Ok(p[idx + 1..].into())
} else {
Ok(p.into())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use alloc::string::String;
use alloc::vec::Vec;

pub fn path_clean(path: String) -> Result<String, String> {
if path.is_empty() {
return Ok(".".into());
}

let separator = std::path::MAIN_SEPARATOR;
let is_absolute = path.starts_with(separator);
let mut out: Vec<&str> = Vec::new();

let segments = path.split(separator);

for segment in segments {
match segment {
"" | "." => continue,
".." => {
if let Some(last) = out.last() {
if *last != ".." {
out.pop();
continue;
}
}
if !is_absolute {
out.push("..");
}
}
_ => out.push(segment),
}
}

if out.is_empty() && is_absolute {
return Ok(separator.to_string());
}

if out.is_empty() {
return Ok(".".into());
}

let joined = out.join(&separator.to_string());
if is_absolute {
Ok(alloc::format!("{}{}", separator, joined))
} else {
Ok(joined)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use alloc::string::String;

pub fn path_dir(path: String) -> Result<String, String> {
if path.is_empty() {
return Ok(".".into());
}

let separator = std::path::MAIN_SEPARATOR;
let mut p = path.as_str();
while p.len() > 1 && p.ends_with(separator) {
p = &p[..p.len() - 1];
}

if p == separator.to_string() {
return Ok(separator.to_string());
}

if let Some(idx) = p.rfind(separator) {
if idx == 0 {
Ok(separator.to_string())
} else {
let mut dir = &p[..idx];
while dir.len() > 1 && dir.ends_with(separator) {
dir = &dir[..dir.len() - 1];
}
Ok(dir.into())
}
} else {
Ok(".".into())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use alloc::string::String;

pub fn path_join(base: String, target: String) -> Result<String, String> {
if base.is_empty() && target.is_empty() {
return Ok("".into());
}
if base.is_empty() {
return super::path_clean_impl::path_clean(target);
}
if target.is_empty() {
return super::path_clean_impl::path_clean(base);
}

let separator = std::path::MAIN_SEPARATOR;
let joined = alloc::format!("{}{}{}", base, separator, target);
super::path_clean_impl::path_clean(joined)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use alloc::string::String;

pub fn path_separator() -> Result<String, String> {
Ok(std::path::MAIN_SEPARATOR.to_string())
}
24 changes: 24 additions & 0 deletions tavern/internal/www/src/assets/eldritch-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,30 @@
"signature": "file.move(src: str, dst: str) -> None",
"description": "The **file.move** method moves a file or directory from `src` to `dst`. If the `dst` directory or file exists it will be deleted before being replaced to ensure consistency across systems."
},
"file.path_abs": {
"signature": "file.path_abs(path: str) -> str",
"description": "Returns an absolute representation of path."
},
"file.path_base": {
"signature": "file.path_base(path: str) -> str",
"description": "Returns the last element of path."
},
"file.path_clean": {
"signature": "file.path_clean(path: str) -> str",
"description": "Returns the shortest path name equivalent to path by purely lexical processing."
},
"file.path_dir": {
"signature": "file.path_dir(path: str) -> str",
"description": "Returns all but the last element of path, typically the path's directory."
},
"file.path_join": {
"signature": "file.path_join(base: str, target: str) -> str",
"description": "Joins two path elements into a single path, separating them with an OS specific separator."
},
"file.path_separator": {
"signature": "file.path_separator() -> str",
"description": "Returns the operating system-specific path separator."
},
"file.parent_dir": {
"signature": "file.parent_dir(path: str) -> str",
"description": "The **file.parent_dir** method returns the parent directory of a give path. Eg `/etc/ssh/sshd_config` -> `/etc/ssh`"
Expand Down
Loading