axfs/api/
file.rs

1use alloc::vec::Vec;
2use axio::{Result, SeekFrom, default_read_to_end, prelude::*};
3use core::fmt;
4
5use crate::fops;
6
7/// A structure representing a type of file with accessors for each file type.
8/// It is returned by [`Metadata::file_type`] method.
9pub type FileType = fops::FileType;
10
11/// Representation of the various permissions on a file.
12pub type Permissions = fops::FilePerm;
13
14/// An object providing access to an open file on the filesystem.
15pub struct File {
16    inner: fops::File,
17}
18
19/// Metadata information about a file.
20pub struct Metadata(pub(super) fops::FileAttr);
21
22/// Options and flags which can be used to configure how a file is opened.
23#[derive(Default, Clone, Debug)]
24pub struct OpenOptions(fops::OpenOptions);
25
26impl OpenOptions {
27    /// Creates a blank new set of options ready for configuration.
28    pub const fn new() -> Self {
29        OpenOptions(fops::OpenOptions::new())
30    }
31
32    /// Sets the option for read access.
33    pub fn read(&mut self, read: bool) -> &mut Self {
34        self.0.read(read);
35        self
36    }
37
38    /// Sets the option for write access.
39    pub fn write(&mut self, write: bool) -> &mut Self {
40        self.0.write(write);
41        self
42    }
43
44    /// Sets the option for the append mode.
45    pub fn append(&mut self, append: bool) -> &mut Self {
46        self.0.append(append);
47        self
48    }
49
50    /// Sets the option for truncating a previous file.
51    pub fn truncate(&mut self, truncate: bool) -> &mut Self {
52        self.0.truncate(truncate);
53        self
54    }
55
56    /// Sets the option to create a new file, or open it if it already exists.
57    pub fn create(&mut self, create: bool) -> &mut Self {
58        self.0.create(create);
59        self
60    }
61
62    /// Sets the option to create a new file, failing if it already exists.
63    pub fn create_new(&mut self, create_new: bool) -> &mut Self {
64        self.0.create_new(create_new);
65        self
66    }
67
68    /// Opens a file at `path` with the options specified by `self`.
69    pub fn open(&self, path: &str) -> Result<File> {
70        fops::File::open(path, &self.0).map(|inner| File { inner })
71    }
72}
73
74impl Metadata {
75    /// Returns the file type for this metadata.
76    pub const fn file_type(&self) -> FileType {
77        self.0.file_type()
78    }
79
80    /// Returns `true` if this metadata is for a directory. The
81    /// result is mutually exclusive to the result of
82    /// [`Metadata::is_file`].
83    pub const fn is_dir(&self) -> bool {
84        self.0.is_dir()
85    }
86
87    /// Returns `true` if this metadata is for a regular file. The
88    /// result is mutually exclusive to the result of
89    /// [`Metadata::is_dir`].
90    pub const fn is_file(&self) -> bool {
91        self.0.is_file()
92    }
93
94    /// Returns the size of the file, in bytes, this metadata is for.
95    #[allow(clippy::len_without_is_empty)]
96    pub const fn len(&self) -> u64 {
97        self.0.size()
98    }
99
100    /// Returns the permissions of the file this metadata is for.
101    pub const fn permissions(&self) -> Permissions {
102        self.0.perm()
103    }
104
105    /// Returns the total size of this file in bytes.
106    pub const fn size(&self) -> u64 {
107        self.0.size()
108    }
109
110    /// Returns the number of blocks allocated to the file, in 512-byte units.
111    pub const fn blocks(&self) -> u64 {
112        self.0.blocks()
113    }
114}
115
116impl fmt::Debug for Metadata {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        f.debug_struct("Metadata")
119            .field("file_type", &self.file_type())
120            .field("is_dir", &self.is_dir())
121            .field("is_file", &self.is_file())
122            .field("permissions", &self.permissions())
123            .finish_non_exhaustive()
124    }
125}
126
127impl File {
128    /// Attempts to open a file in read-only mode.
129    pub fn open(path: &str) -> Result<Self> {
130        OpenOptions::new().read(true).open(path)
131    }
132
133    /// Opens a file in write-only mode.
134    pub fn create(path: &str) -> Result<Self> {
135        OpenOptions::new()
136            .write(true)
137            .create(true)
138            .truncate(true)
139            .open(path)
140    }
141
142    /// Creates a new file in read-write mode; error if the file exists.
143    pub fn create_new(path: &str) -> Result<Self> {
144        OpenOptions::new()
145            .read(true)
146            .write(true)
147            .create_new(true)
148            .open(path)
149    }
150
151    /// Returns a new OpenOptions object.
152    pub fn options() -> OpenOptions {
153        OpenOptions::new()
154    }
155
156    /// Truncates or extends the underlying file, updating the size of
157    /// this file to become `size`.
158    pub fn set_len(&self, size: u64) -> Result<()> {
159        self.inner.truncate(size)
160    }
161
162    /// Queries metadata about the underlying file.
163    pub fn metadata(&self) -> Result<Metadata> {
164        self.inner.get_attr().map(Metadata)
165    }
166}
167
168impl Read for File {
169    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
170        self.inner.read(buf)
171    }
172
173    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
174        default_read_to_end(
175            self,
176            buf,
177            self.metadata().ok().map(|metadata| metadata.size() as _),
178        )
179    }
180}
181
182impl Write for File {
183    fn write(&mut self, buf: &[u8]) -> Result<usize> {
184        self.inner.write(buf)
185    }
186
187    fn flush(&mut self) -> Result<()> {
188        self.inner.flush()
189    }
190}
191
192impl Seek for File {
193    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
194        self.inner.seek(pos)
195    }
196}