libsubconverter/utils/
file_std.rs

1use std::fs;
2use std::io::{self, Read};
3use std::path::Path;
4
5/// Read a file into a string
6pub fn read_file(path: &str) -> Result<String, io::Error> {
7    let mut file = fs::File::open(path)?;
8    let mut contents = String::new();
9    file.read_to_string(&mut contents)?;
10    Ok(contents)
11}
12
13/// Async version of read_file that reads a file into a string asynchronously
14///
15/// # Arguments
16/// * `path` - Path to the file to read
17///
18/// # Returns
19/// * `Ok(String)` - The file contents
20/// * `Err(io::Error)` - If the file can't be read
21pub async fn read_file_async(path: &str) -> Result<String, io::Error> {
22    tokio::fs::read_to_string(path).await
23}
24
25/// Check if a file exists
26pub async fn file_exists(path: &str) -> bool {
27    tokio::fs::metadata(path).await.is_ok()
28}
29
30/// Read the contents of a file as a string
31///
32/// # Arguments
33/// * `path` - Path to the file to read
34/// * `base_path` - Optional base path for security checking
35///
36/// # Returns
37/// * `Ok(String)` - The file contents
38/// * `Err(io::Error)` - If the file can't be read
39pub fn file_get<P: AsRef<Path>>(path: P, base_path: Option<&str>) -> io::Result<String> {
40    if let Some(base_path) = base_path {
41        match path.as_ref().to_str() {
42            Some(path_str) => {
43                if !path_str.starts_with(base_path) {
44                    return Err(io::Error::new(
45                        io::ErrorKind::InvalidInput,
46                        "File path is not within the base path",
47                    ));
48                }
49            }
50            None => {
51                return Err(io::Error::new(
52                    io::ErrorKind::InvalidInput,
53                    "File path is not a valid UTF-8 string",
54                ));
55            }
56        }
57    }
58    fs::read_to_string(path)
59}
60
61/// Copy a file from source to destination
62pub async fn copy_file(src: &str, dst: &str) -> io::Result<()> {
63    // Check if source exists
64    if !Path::new(src).exists() {
65        return Err(io::Error::new(
66            io::ErrorKind::NotFound,
67            format!("Source file {} not found", src),
68        ));
69    }
70
71    // Create parent directories if they don't exist
72    if let Some(parent) = Path::new(dst).parent() {
73        fs::create_dir_all(parent)?;
74    }
75
76    // Copy the file
77    fs::copy(src, dst)?;
78    Ok(())
79}
80
81/// Async version of file_get that reads file contents asynchronously
82///
83/// # Arguments
84/// * `path` - Path to the file to read
85/// * `base_path` - Optional base path for security checking
86///
87/// # Returns
88/// * `Ok(String)` - The file contents
89/// * `Err(io::Error)` - If the file can't be read
90pub async fn file_get_async<P: AsRef<Path>>(
91    path: P,
92    base_path: Option<&str>,
93) -> io::Result<String> {
94    if let Some(base_path) = base_path {
95        match path.as_ref().to_str() {
96            Some(path_str) => {
97                if !path_str.starts_with(base_path) {
98                    return Err(io::Error::new(
99                        io::ErrorKind::InvalidInput,
100                        "File path is not within the base path",
101                    ));
102                }
103            }
104            None => {
105                return Err(io::Error::new(
106                    io::ErrorKind::InvalidInput,
107                    "File path is not a valid UTF-8 string",
108                ));
109            }
110        }
111    }
112    tokio::fs::read_to_string(path).await
113}