nstd_sys/
fs.rs

1//! Provides access to the file system.
2pub mod file;
3use crate::{
4    core::{optional::NSTDOptional, result::NSTDResult, slice::NSTDSlice, str::NSTDStr},
5    io::{NSTDIOBufferResult, NSTDIOError, NSTDIOStringResult},
6    string::NSTDString,
7    time::{NSTDOptionalTime, NSTDTime},
8    vec::NSTDVec,
9    NSTDUInt64, NSTDUInt8,
10};
11use nstdapi::nstdapi;
12use std::fs::File;
13
14/// A bit flag describing a file with read access.
15pub const NSTD_FILE_PERMISSION_READ: NSTDUInt8 = 1;
16
17/// Describes the type of a file.
18#[nstdapi]
19#[derive(Clone, Copy, PartialEq, Eq)]
20#[allow(non_camel_case_types)]
21pub enum NSTDFileType {
22    /// An unknown file type.
23    NSTD_FILE_TYPE_UNKNOWN,
24    /// A normal text/binary file.
25    NSTD_FILE_TYPE_REGULAR,
26    /// A directory/folder.
27    NSTD_FILE_TYPE_DIRECTORY,
28    /// A symbolic link.
29    NSTD_FILE_TYPE_SYMLINK,
30}
31
32/// Represents file metadata.
33#[nstdapi]
34#[derive(Clone, Copy)]
35pub struct NSTDFileMetadata {
36    /// The size of the file in bytes.
37    pub size: NSTDUInt64,
38    /// The time that the file was created.
39    pub created: NSTDOptionalTime,
40    /// The time that the file was last accessed.
41    pub accessed: NSTDOptionalTime,
42    /// The time that the file was last modified.
43    pub modified: NSTDOptionalTime,
44    /// The file type.
45    pub file_type: NSTDFileType,
46    /// A bit mask representing the file's permissions.
47    pub permissions: NSTDUInt8,
48}
49
50/// A result type returned from `nstd_fs_metadata`.
51pub type NSTDFileMetadataResult = NSTDResult<NSTDFileMetadata, NSTDIOError>;
52
53/// Creates a new file on the file system.
54///
55/// # Parameters:
56///
57/// - `const NSTDStr *name` - The name of the new file.
58///
59/// # Returns
60///
61/// `NSTDIOError errc` - The I/O operation error code.
62///
63/// # Safety
64///
65/// This operation can cause undefined behavior if `name`'s data is invalid.
66#[inline]
67#[nstdapi]
68pub unsafe fn nstd_fs_create_file(name: &NSTDStr) -> NSTDIOError {
69    if let Err(err) = File::create(name.as_str()) {
70        return NSTDIOError::from_err(err.kind());
71    }
72    NSTDIOError::NSTD_IO_ERROR_NONE
73}
74
75/// Creates a new directory on the file system.
76///
77/// # Parameters:
78///
79/// - `const NSTDStr *name` - The name of the new directory.
80///
81/// # Returns
82///
83/// `NSTDIOError errc` - The I/O operation error code.
84///
85/// # Safety
86///
87/// This operation can cause undefined behavior if `name`'s data is invalid.
88#[inline]
89#[nstdapi]
90pub unsafe fn nstd_fs_create_dir(name: &NSTDStr) -> NSTDIOError {
91    if let Err(err) = std::fs::create_dir(name.as_str()) {
92        return NSTDIOError::from_err(err.kind());
93    }
94    NSTDIOError::NSTD_IO_ERROR_NONE
95}
96
97/// Recursively creates new directories on the file system.
98///
99/// # Parameters:
100///
101/// - `const NSTDStr *name` - A path to the new directory.
102///
103/// # Returns
104///
105/// `NSTDIOError errc` - The I/O operation error code.
106///
107/// # Safety
108///
109/// This operation can cause undefined behavior if `name`'s data is invalid.
110#[inline]
111#[nstdapi]
112pub unsafe fn nstd_fs_create_dirs(name: &NSTDStr) -> NSTDIOError {
113    if let Err(err) = std::fs::create_dir_all(name.as_str()) {
114        return NSTDIOError::from_err(err.kind());
115    }
116    NSTDIOError::NSTD_IO_ERROR_NONE
117}
118
119/// Removes a file from the file system.
120///
121/// # Parameters:
122///
123/// - `const NSTDStr *name` - The name of the file to delete.
124///
125/// # Returns
126///
127/// `NSTDIOError errc` - The I/O operation error code.
128///
129/// # Safety
130///
131/// This operation can cause undefined behavior if `name`'s data is invalid.
132#[inline]
133#[nstdapi]
134pub unsafe fn nstd_fs_remove_file(name: &NSTDStr) -> NSTDIOError {
135    if let Err(err) = std::fs::remove_file(name.as_str()) {
136        return NSTDIOError::from_err(err.kind());
137    }
138    NSTDIOError::NSTD_IO_ERROR_NONE
139}
140
141/// Removes a directory from the file system.
142///
143/// # Parameters:
144///
145/// - `const NSTDStr *name` - The name of the directory to delete.
146///
147/// # Returns
148///
149/// `NSTDIOError errc` - The I/O operation error code.
150///
151/// # Safety
152///
153/// This operation can cause undefined behavior if `name`'s data is invalid.
154#[inline]
155#[nstdapi]
156pub unsafe fn nstd_fs_remove_dir(name: &NSTDStr) -> NSTDIOError {
157    if let Err(err) = std::fs::remove_dir(name.as_str()) {
158        return NSTDIOError::from_err(err.kind());
159    }
160    NSTDIOError::NSTD_IO_ERROR_NONE
161}
162
163/// Recursively removes directories on the file system.
164///
165/// # Parameters:
166///
167/// - `const NSTDStr *name` - A path to the directory to remove.
168///
169/// # Returns
170///
171/// `NSTDIOError errc` - The I/O operation error code.
172///
173/// # Safety
174///
175/// This operation can cause undefined behavior if `name`'s data is invalid.
176#[inline]
177#[nstdapi]
178pub unsafe fn nstd_fs_remove_dirs(name: &NSTDStr) -> NSTDIOError {
179    if let Err(err) = std::fs::remove_dir_all(name.as_str()) {
180        return NSTDIOError::from_err(err.kind());
181    }
182    NSTDIOError::NSTD_IO_ERROR_NONE
183}
184
185/// Reads the contents of a file.
186///
187/// # Parameters:
188///
189/// - `const NSTDStr *path` - A path to the file to read.
190///
191/// # Returns
192///
193/// `NSTDIOBufferResult contents` - The file's contents, or the I/O operation error code on failure.
194///
195/// # Safety
196///
197/// This operation can cause undefined behavior if `path`'s data is invalid.
198#[nstdapi]
199pub unsafe fn nstd_fs_read(path: &NSTDStr) -> NSTDIOBufferResult<'_> {
200    match std::fs::read(path.as_str()) {
201        Ok(contents) => NSTDResult::Ok(NSTDVec::from_vec(contents)),
202        Err(err) => NSTDResult::Err(NSTDIOError::from_err(err.kind())),
203    }
204}
205
206/// Reads the contents of a file into a UTF-8 string.
207///
208/// # Parameters:
209///
210/// - `const NSTDStr *path` - A path to the file to read.
211///
212/// # Returns
213///
214/// `NSTDIOStringResult contents` - The file's contents, or the I/O operation error code on failure.
215///
216/// # Safety
217///
218/// This operation can cause undefined behavior if `path`'s data is invalid.
219#[nstdapi]
220pub unsafe fn nstd_fs_read_to_string(path: &NSTDStr) -> NSTDIOStringResult<'_> {
221    match std::fs::read_to_string(path.as_str()) {
222        Ok(contents) => NSTDResult::Ok(NSTDString::from_string(contents)),
223        Err(err) => NSTDResult::Err(NSTDIOError::from_err(err.kind())),
224    }
225}
226
227/// Overwrites the contents of a file.
228///
229/// # Parameters:
230///
231/// - `const NSTDStr *path` - A path to the file to write to.
232///
233/// - `const NSTDSlice *content` - The new content to write to the file.
234///
235/// # Returns
236///
237/// `NSTDIOError errc` - The I/O operation error code.
238///
239/// # Safety
240///
241/// This operation can cause undefined behavior if either `path` or `content`'s data is invalid.
242#[nstdapi]
243pub unsafe fn nstd_fs_write(path: &NSTDStr, content: &NSTDSlice) -> NSTDIOError {
244    content.as_slice().map_or(
245        NSTDIOError::NSTD_IO_ERROR_INVALID_INPUT,
246        |bytes| match std::fs::write(path.as_str(), bytes) {
247            Ok(()) => NSTDIOError::NSTD_IO_ERROR_NONE,
248            Err(err) => NSTDIOError::from_err(err.kind()),
249        },
250    )
251}
252
253/// Renames a file or directory, replacing the destination if it already exists.
254///
255/// # Parameters:
256///
257/// - `const NSTDStr *from` - The original name of the file/directory.
258///
259/// - `const NSTDStr *to` - The new name of the file/dir.
260///
261/// # Returns
262///
263/// `NSTDIOError errc` - The I/O operation error code.
264///
265/// # Safety
266///
267/// This operation can cause undefined behavior if either `to` or `from`'s data is invalid.
268#[inline]
269#[nstdapi]
270pub unsafe fn nstd_fs_rename(from: &NSTDStr, to: &NSTDStr) -> NSTDIOError {
271    if let Err(err) = std::fs::rename(from.as_str(), to.as_str()) {
272        return NSTDIOError::from_err(err.kind());
273    }
274    NSTDIOError::NSTD_IO_ERROR_NONE
275}
276
277/// Copies the contents and permissions of one file to another.
278///
279/// # Parameters:
280///
281/// - `const NSTDStr *from` - The source file.
282///
283/// - `const NSTDStr *to` - The destination file.
284///
285/// # Returns
286///
287/// `NSTDIOError errc` - The I/O operation error code.
288///
289/// # Safety
290///
291/// This operation can cause undefined behavior if either `to` or `from`'s data is invalid.
292#[inline]
293#[nstdapi]
294pub unsafe fn nstd_fs_copy(from: &NSTDStr, to: &NSTDStr) -> NSTDIOError {
295    if let Err(err) = std::fs::copy(from.as_str(), to.as_str()) {
296        return NSTDIOError::from_err(err.kind());
297    }
298    NSTDIOError::NSTD_IO_ERROR_NONE
299}
300
301/// Returns the absolute path of a file system item.
302///
303/// # Parameters:
304///
305/// - `const NSTDStr *path` - A relative path to the file system item.
306///
307/// # Returns
308///
309/// `NSTDIOStringResult contents` - The absolute version of `path`, or the I/O operation error code
310/// on failure.
311///
312/// # Safety
313///
314/// This operation can cause undefined behavior if `path`'s data is invalid.
315#[nstdapi]
316pub unsafe fn nstd_fs_absolute(path: &NSTDStr) -> NSTDIOStringResult<'_> {
317    match std::fs::canonicalize(path.as_str()) {
318        Ok(path) => path.into_os_string().into_string().map_or(
319            NSTDResult::Err(NSTDIOError::NSTD_IO_ERROR_INVALID_DATA),
320            |path| NSTDResult::Ok(NSTDString::from_string(path)),
321        ),
322        Err(err) => NSTDResult::Err(NSTDIOError::from_err(err.kind())),
323    }
324}
325
326/// Retrieves metadata about a file pointed to by `path`.
327///
328/// # Parameters:
329///
330/// - `const NSTDStr *path` - A path to the file to retrieve metadata for.
331///
332/// # Returns
333///
334/// `NSTDFileMetadataResult metadata` - Metadata describing the file.
335///
336/// # Safety
337///
338/// `path` must be valid for reads.
339#[nstdapi]
340pub unsafe fn nstd_fs_metadata(path: &NSTDStr) -> NSTDFileMetadataResult {
341    match std::fs::metadata(path.as_str()) {
342        Ok(metadata) => NSTDResult::Ok(NSTDFileMetadata {
343            size: metadata.len(),
344            created: metadata.created().map_or(NSTDOptional::None, |t| {
345                NSTDOptional::Some(NSTDTime::from(t))
346            }),
347            accessed: metadata.accessed().map_or(NSTDOptional::None, |t| {
348                NSTDOptional::Some(NSTDTime::from(t))
349            }),
350            modified: metadata.modified().map_or(NSTDOptional::None, |t| {
351                NSTDOptional::Some(NSTDTime::from(t))
352            }),
353            file_type: {
354                if metadata.is_file() {
355                    NSTDFileType::NSTD_FILE_TYPE_REGULAR
356                } else if metadata.is_dir() {
357                    NSTDFileType::NSTD_FILE_TYPE_DIRECTORY
358                } else if metadata.is_symlink() {
359                    NSTDFileType::NSTD_FILE_TYPE_SYMLINK
360                } else {
361                    NSTDFileType::NSTD_FILE_TYPE_UNKNOWN
362                }
363            },
364            permissions: metadata.permissions().readonly().into(),
365        }),
366        Err(err) => NSTDResult::Err(NSTDIOError::from_err(err.kind())),
367    }
368}