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}