aether/builtins/
filesystem.rs

1// src/builtins/filesystem.rs
2//! 文件系统IO操作函数
3
4use crate::evaluator::RuntimeError;
5use crate::sandbox::get_filesystem_validator;
6use crate::value::Value;
7use std::fs;
8use std::path::Path;
9
10/// 辅助函数:安全地获取字符串参数
11fn get_string(val: &Value) -> Result<String, RuntimeError> {
12    match val {
13        Value::String(s) => Ok(s.clone()),
14        _ => Err(RuntimeError::TypeErrorDetailed {
15            expected: "String".to_string(),
16            got: format!("{:?}", val),
17        }),
18    }
19}
20
21/// 辅助函数:验证路径(如果配置了验证器)
22fn validate_path(path_str: &str) -> Result<std::path::PathBuf, RuntimeError> {
23    // 如果配置了路径验证器,使用它验证路径
24    if let Some(validator) = get_filesystem_validator() {
25        let path = Path::new(path_str);
26        validator
27            .validate_and_normalize(path)
28            .map_err(|e| RuntimeError::CustomError(format!("Path validation failed: {}", e)))
29    } else {
30        // 没有配置验证器,直接使用原始路径
31        Ok(std::path::PathBuf::from(path_str))
32    }
33}
34
35/// 读取文件内容
36///
37/// # 参数
38/// - 文件路径
39///
40/// # 返回
41/// 文件内容(字符串)
42///
43/// # 安全性
44/// 需要启用文件系统权限
45pub fn read_file(args: &[Value]) -> Result<Value, RuntimeError> {
46    if args.is_empty() {
47        return Err(RuntimeError::WrongArity {
48            expected: 1,
49            got: 0,
50        });
51    }
52
53    let path_str = get_string(&args[0])?;
54
55    // 验证路径(如果配置了验证器)
56    let validated_path = validate_path(&path_str)?;
57
58    match fs::read_to_string(&validated_path) {
59        Ok(content) => Ok(Value::String(content)),
60        Err(e) => Err(RuntimeError::CustomError(format!(
61            "Failed to read file '{}': {}",
62            validated_path.display(),
63            e
64        ))),
65    }
66}
67
68/// 写入文件内容(覆盖)
69///
70/// # 参数
71/// - 文件路径
72/// - 文件内容
73///
74/// # 返回
75/// 成功返回 true
76///
77/// # 安全性
78/// 需要启用文件系统权限
79pub fn write_file(args: &[Value]) -> Result<Value, RuntimeError> {
80    if args.len() < 2 {
81        return Err(RuntimeError::WrongArity {
82            expected: 2,
83            got: args.len(),
84        });
85    }
86
87    let path_str = get_string(&args[0])?;
88    let content = get_string(&args[1])?;
89
90    // 验证路径
91    let validated_path = validate_path(&path_str)?;
92
93    match fs::write(&validated_path, content) {
94        Ok(_) => Ok(Value::Boolean(true)),
95        Err(e) => Err(RuntimeError::CustomError(format!(
96            "Failed to write file '{}': {}",
97            validated_path.display(),
98            e
99        ))),
100    }
101}
102
103/// 追加文件内容
104///
105/// # 参数
106/// - 文件路径
107/// - 追加内容
108///
109/// # 返回
110/// 成功返回 true
111///
112/// # 安全性
113/// 需要启用文件系统权限
114pub fn append_file(args: &[Value]) -> Result<Value, RuntimeError> {
115    if args.len() < 2 {
116        return Err(RuntimeError::WrongArity {
117            expected: 2,
118            got: args.len(),
119        });
120    }
121
122    let path_str = get_string(&args[0])?;
123    let content = get_string(&args[1])?;
124
125    // 验证路径
126    let validated_path = validate_path(&path_str)?;
127
128    match fs::OpenOptions::new()
129        .create(true)
130        .append(true)
131        .open(&validated_path)
132    {
133        Ok(mut file) => {
134            use std::io::Write;
135            match file.write_all(content.as_bytes()) {
136                Ok(_) => Ok(Value::Boolean(true)),
137                Err(e) => Err(RuntimeError::CustomError(format!(
138                    "Failed to append to file '{}': {}",
139                    validated_path.display(),
140                    e
141                ))),
142            }
143        }
144        Err(e) => Err(RuntimeError::CustomError(format!(
145            "Failed to open file '{}': {}",
146            validated_path.display(),
147            e
148        ))),
149    }
150}
151
152/// 删除文件
153///
154/// # 参数
155/// - 文件路径
156///
157/// # 返回
158/// 成功返回 true
159///
160/// # 安全性
161/// 需要启用文件系统权限
162pub fn delete_file(args: &[Value]) -> Result<Value, RuntimeError> {
163    if args.is_empty() {
164        return Err(RuntimeError::WrongArity {
165            expected: 1,
166            got: 0,
167        });
168    }
169
170    let path_str = get_string(&args[0])?;
171
172    // 验证路径
173    let validated_path = validate_path(&path_str)?;
174
175    match fs::remove_file(&validated_path) {
176        Ok(_) => Ok(Value::Boolean(true)),
177        Err(e) => Err(RuntimeError::CustomError(format!(
178            "Failed to delete file '{}': {}",
179            validated_path.display(),
180            e
181        ))),
182    }
183}
184
185/// 检查文件是否存在
186///
187/// # 参数
188/// - 文件路径
189///
190/// # 返回
191/// 存在返回 true,不存在返回 false
192pub fn file_exists(args: &[Value]) -> Result<Value, RuntimeError> {
193    if args.is_empty() {
194        return Err(RuntimeError::WrongArity {
195            expected: 1,
196            got: 0,
197        });
198    }
199
200    let path = get_string(&args[0])?;
201    Ok(Value::Boolean(Path::new(&path).exists()))
202}
203
204/// 列出目录内容
205///
206/// # 参数
207/// - 目录路径
208///
209/// # 返回
210/// 文件和目录名称的数组
211///
212/// # 安全性
213/// 需要启用文件系统权限
214pub fn list_dir(args: &[Value]) -> Result<Value, RuntimeError> {
215    if args.is_empty() {
216        return Err(RuntimeError::WrongArity {
217            expected: 1,
218            got: 0,
219        });
220    }
221
222    let path_str = get_string(&args[0])?;
223
224    // 验证路径
225    let validated_path = validate_path(&path_str)?;
226
227    match fs::read_dir(&validated_path) {
228        Ok(entries) => {
229            let mut items = Vec::new();
230            for entry in entries {
231                match entry {
232                    Ok(e) => {
233                        if let Some(name) = e.file_name().to_str() {
234                            items.push(Value::String(name.to_string()));
235                        }
236                    }
237                    Err(e) => {
238                        return Err(RuntimeError::CustomError(format!(
239                            "Failed to read directory entry: {}",
240                            e
241                        )));
242                    }
243                }
244            }
245            Ok(Value::Array(items))
246        }
247        Err(e) => Err(RuntimeError::CustomError(format!(
248            "Failed to list directory '{}': {}",
249            validated_path.display(),
250            e
251        ))),
252    }
253}
254
255/// 创建目录
256///
257/// # 参数
258/// - 目录路径
259///
260/// # 返回
261/// 成功返回 true
262///
263/// # 安全性
264/// 需要启用文件系统权限
265pub fn create_dir(args: &[Value]) -> Result<Value, RuntimeError> {
266    if args.is_empty() {
267        return Err(RuntimeError::WrongArity {
268            expected: 1,
269            got: 0,
270        });
271    }
272
273    let path_str = get_string(&args[0])?;
274
275    // 验证路径
276    let validated_path = validate_path(&path_str)?;
277
278    match fs::create_dir_all(&validated_path) {
279        Ok(_) => Ok(Value::Boolean(true)),
280        Err(e) => Err(RuntimeError::CustomError(format!(
281            "Failed to create directory '{}': {}",
282            validated_path.display(),
283            e
284        ))),
285    }
286}