///|
pub fn cli_argument_start() -> Int32 {
1
}
///|
#borrow(path, data)
extern "C" fn atomic_write_native(
path : Bytes,
data : Bytes,
size : Int32,
overwrite : Bool,
) -> Bytes = "moonar_atomic_write"
///|
#borrow(base, target)
extern "C" fn check_member_path_native(base : Bytes, target : Bytes) -> Bytes = "moonar_check_member_path"
///|
#borrow(path)
extern "C" fn canonical_path_native(path : Bytes) -> Bytes = "moonar_canonical_path"
///|
pub fn canonical_path(path : String) -> Result[String, String] {
let path = match io_path_bytes(path) {
Ok(path) => path
Err(message) => return Err(message)
}
let result = canonical_path_native(path)
if !result.is_empty() && result[0] == b'\x00' {
Ok(@utf8.decode(result[1:])) catch {
_ => Err("resolved path is not UTF-8")
}
} else {
Err(@utf8.decode_lossy(result[:]))
}
}
///|
/// Publish a complete file using an exclusively created temporary file in the
/// destination directory. An unsuccessful operation leaves the old file intact.
pub fn atomic_write(
path : String,
data : Bytes,
overwrite : Bool,
) -> Result[Unit, String] {
let path = match io_path_bytes(path) {
Ok(path) => path
Err(message) => return Err(message)
}
let error = atomic_write_native(path, data, data.length(), overwrite)
if error.is_empty() {
Ok(())
} else {
Err(@utf8.decode_lossy(error[:]))
}
}
///|
/// Resolve existing paths and require the target to remain inside base.
/// Callers must avoid concurrent path mutation between this check and opening.
pub fn check_member_path(
base : String,
target : String,
) -> Result[Unit, String] {
let base = match io_path_bytes(base) {
Ok(path) => path
Err(message) => return Err(message)
}
let target = match io_path_bytes(target) {
Ok(path) => path
Err(message) => return Err(message)
}
let error = check_member_path_native(base, target)
if error.is_empty() {
Ok(())
} else {
Err(@utf8.decode_lossy(error[:]))
}
}