wsd/
fs.rs

1//!The intuitive file system module
2//!
3//! Demo of the intuitive File, call methods like C API convention, check the returned integer for status, 0 means success, negative value means error.
4//!
5//! ```rust,no_run
6//!use wsd::fs::*;
7//!
8//!fn test() -> i32 {
9//!    let mut f = File::new();
10//!     if f.open("test.txt", O_CREATE | O_RW) != 0 {
11//!         // check the error
12//!         println!("Error: {}", f.error());
13//!        return -1;
14//!    }
15//!
16//!    let data = "Hello World!";
17//!    let n = f.write(data);
18//!    if n < 0 {
19//!        // write error
20//!    }
21//!
22//!    f.rewind();
23//!    let mut buf = [0; 4096];
24//!    let n = f.read(&mut buf);
25//!    if n > 0 {
26//!        // success to read n bytes
27//!    }
28//!
29//!    f.seek(256, SEEK_SET);
30//!    f.write("more data");
31//!
32//!    f.close();
33//!
34//!    return 0;
35//!}
36//!
37//!```
38use std::io::prelude::*;
39use std::path::Path;
40
41/// Create and open the file
42pub const O_CREATE: u32 = 1 << 1;
43/// Append only
44pub const O_APPEND: u32 = 1 << 2;
45/// Non blocking to [`File::write`]
46pub const O_NONBLOCK: u32 = 1 << 3;
47/// Read only
48pub const O_READ: u32 = 1 << 4;
49/// Write only
50pub const O_WRITE: u32 = 1 << 5;
51/// Read and write
52pub const O_RW: u32 = O_READ | O_WRITE;
53/// Causes the file to be truncated if it exists
54pub const O_TRUNCATE: u32 = 1 << 6;
55
56/// Seek to absolute position
57pub const SEEK_SET: i32 = 1;
58/// Seek to relative position from current
59pub const SEEK_CUR: i32 = 2;
60/// Seek to relative position from end
61pub const SEEK_END: i32 = 3;
62
63#[allow(non_camel_case_types)]
64type int = i32;
65
66/// Create directories recursively
67pub fn mkdir<P: AsRef<Path>>(path: P) -> int {
68    if let Err(_) = std::fs::create_dir_all(path) {
69        return -1;
70    }
71    return 0;
72}
73
74/// Remove a file
75pub fn remove<T: AsRef<Path>>(path: T) -> int {
76    if let Err(_) = std::fs::remove_file(path) {
77        return -1;
78    }
79    return 0;
80}
81
82/// Intuitive File
83pub struct File {
84    pod: Option<std::fs::File>,
85    path: String,
86    flags: u32,
87    error: std::io::Error,
88}
89
90impl File {
91    /// Returns a new File instance
92    pub fn new() -> Self {
93        return File {
94            pod: None,
95            path: "".to_string(),
96            flags: 0,
97            error: std::io::Error::new(std::io::ErrorKind::Other, ""),
98        };
99    }
100
101    /// Open a file with given flags
102    pub fn open<T: AsRef<str>>(&mut self, path: T, flags: u32) -> int {
103        let mut options = std::fs::File::options();
104
105        self.pod = None;
106        self.path = path.as_ref().to_string();
107
108        self.flags = flags;
109        if flags == 0 {
110            self.flags |= O_READ;
111        }
112
113        options.create(self.flags & O_CREATE != 0);
114        options.append(self.flags & O_APPEND != 0);
115        options.read(self.flags & O_READ != 0);
116        options.write(self.flags & O_WRITE != 0);
117        options.truncate(self.flags & O_TRUNCATE != 0);
118
119        let ret = options.open(path.as_ref());
120        match ret {
121            Ok(f) => {
122                self.pod = Some(f);
123            }
124            Err(e) => {
125                self.error = e;
126                return -1;
127            }
128        }
129
130        return 0;
131    }
132
133    /// Simply drop the inner file descriptor
134    pub fn close(&mut self) {
135        self.pod = None;
136    }
137
138    /// Returns the path of the file
139    pub fn path(&self) -> &String {
140        return &self.path;
141    }
142
143    /// Returns the last error of calls
144    pub fn error(&self) -> &std::io::Error {
145        return &self.error;
146    }
147
148    /// Write all data unless [`O_NONBLOCK`] flag was set
149    pub fn write<Buffer: AsRef<[u8]>>(&mut self, data: Buffer) -> int {
150        let mut i = 0;
151        let buf = data.as_ref();
152        let n = buf.len() as i32;
153
154        if self.is_none() {
155            return -1;
156        }
157
158        let nb = self.flags & O_NONBLOCK != 0;
159        let mut fd = self.fd();
160
161        while i < n {
162            let off = i as usize;
163            let ret = fd.write(&buf[off..]);
164            match ret {
165                Ok(n) => i += n as i32,
166                Err(e) => {
167                    self.error = e;
168                    break;
169                }
170            }
171            if nb {
172                break;
173            }
174        }
175
176        return i;
177    }
178
179    pub fn read_to_end(&mut self, buf: &mut Vec<u8>) -> i32 {
180        if self.is_none() {
181            return -1;
182        }
183
184        match self.fd().read_to_end(buf)  {
185            Ok(n) => {
186                return  n as i32;
187            },
188            Err(e) =>  {
189                self.error = e;
190            }
191        }
192
193        return -1;
194    }
195
196    /// Read data into buffer
197    pub fn read(&mut self, buf: &mut [u8]) -> int {
198        if self.is_none() {
199            return -1;
200        }
201
202        let mut i = 0;
203        let mut fd = self.fd();
204
205        let ret = fd.read(buf);
206        match ret {
207            Ok(n) => {
208                i = n as i32;
209            }
210            Err(e) => {
211                self.error = e;
212            }
213        }
214
215        return i;
216    }
217
218    /// Flush the file
219    pub fn flush(&mut self) -> int {
220        if self.is_none() {
221            return -1;
222        }
223
224        if let Err(e) = self.fd().flush() {
225            self.error = e;
226            return -1;
227        }
228
229        return 0;
230    }
231
232    /// Seek to a position
233    /// * `offset` - relative position
234    /// * `whence` - One of: [`SEEK_SET`], [`SEEK_CUR`], [`SEEK_END`]
235    pub fn seek(&mut self, offset: i64, whence: int) -> i64 {
236        if self.is_none() {
237            return -1;
238        }
239
240        let w;
241        let mut off = -1;
242
243        match whence {
244            SEEK_SET => {
245                w = std::io::SeekFrom::Start(offset as u64);
246            }
247            SEEK_CUR => {
248                w = std::io::SeekFrom::Current(offset);
249            }
250            SEEK_END => {
251                w = std::io::SeekFrom::End(offset);
252            }
253            _ => {
254                return off;
255            }
256        }
257
258        let ret = self.fd().seek(w);
259        match ret {
260            Ok(n) => {
261                off = n as i64;
262            }
263            Err(e) => {
264                self.error = e;
265            }
266        }
267
268        return off;
269    }
270
271    /// Reset the position
272    pub fn rewind(&mut self) -> int {
273        if self.seek(0, SEEK_SET) < 0 {
274            return -1;
275        }
276        return 0;
277    }
278
279    /// Returns the current position
280    pub fn position(&mut self) -> i64 {
281        return self.seek(0, SEEK_CUR);
282    }
283
284    /// Check if inner file descriptor is none
285    pub fn is_none(&self) -> bool {
286        return self.pod.is_none();
287    }
288
289    /// Returns a reference to inner file descriptor
290    pub fn fd(&mut self) -> Box<&mut std::fs::File> {
291        return Box::new(self.pod.as_mut().unwrap());
292    }
293}