axfs/api/
file.rs

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