xref: /relibc/src/fs.rs (revision b8c50c7c6421d1868a95e57ac1553557cb2314b1)
1 use crate::{
2     c_str::CStr,
3     header::{
4         fcntl::O_CREAT,
5         unistd::{SEEK_CUR, SEEK_END, SEEK_SET},
6     },
7     io,
8     platform::{types::*, Pal, Sys},
9 };
10 use core::ops::Deref;
11 
12 pub struct File {
13     pub fd: c_int,
14     /// To avoid self referential FILE struct that needs both a reader and a writer,
15     /// make "reference" files that share fd but don't close on drop.
16     pub reference: bool,
17 }
18 
19 impl File {
new(fd: c_int) -> Self20     pub fn new(fd: c_int) -> Self {
21         Self {
22             fd,
23             reference: false,
24         }
25     }
26 
open(path: &CStr, oflag: c_int) -> io::Result<Self>27     pub fn open(path: &CStr, oflag: c_int) -> io::Result<Self> {
28         match Sys::open(path, oflag, 0) {
29             -1 => Err(io::last_os_error()),
30             ok => Ok(Self::new(ok)),
31         }
32     }
33 
create(path: &CStr, oflag: c_int, mode: mode_t) -> io::Result<Self>34     pub fn create(path: &CStr, oflag: c_int, mode: mode_t) -> io::Result<Self> {
35         match Sys::open(path, oflag | O_CREAT, mode) {
36             -1 => Err(io::last_os_error()),
37             ok => Ok(Self::new(ok)),
38         }
39     }
40 
sync_all(&self) -> io::Result<()>41     pub fn sync_all(&self) -> io::Result<()> {
42         match Sys::fsync(self.fd) {
43             -1 => Err(io::last_os_error()),
44             _ok => Ok(()),
45         }
46     }
47 
set_len(&self, size: u64) -> io::Result<()>48     pub fn set_len(&self, size: u64) -> io::Result<()> {
49         match Sys::ftruncate(self.fd, size as off_t) {
50             -1 => Err(io::last_os_error()),
51             _ok => Ok(()),
52         }
53     }
54 
try_clone(&self) -> io::Result<Self>55     pub fn try_clone(&self) -> io::Result<Self> {
56         match Sys::dup(self.fd) {
57             -1 => Err(io::last_os_error()),
58             ok => Ok(Self::new(ok)),
59         }
60     }
61 
62     /// Create a new file pointing to the same underlying descriptor. This file
63     /// will know it's a "reference" and won't close the fd. It will, however,
64     /// not prevent the original file from closing the fd.
get_ref(&self) -> Self65     pub unsafe fn get_ref(&self) -> Self {
66         Self {
67             fd: self.fd,
68             reference: true,
69         }
70     }
71 }
72 
73 impl io::Read for &File {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>74     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
75         match Sys::read(self.fd, buf) {
76             -1 => Err(io::last_os_error()),
77             ok => Ok(ok as usize),
78         }
79     }
80 }
81 
82 impl io::Write for &File {
write(&mut self, buf: &[u8]) -> io::Result<usize>83     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
84         match Sys::write(self.fd, buf) {
85             -1 => Err(io::last_os_error()),
86             ok => Ok(ok as usize),
87         }
88     }
89 
flush(&mut self) -> io::Result<()>90     fn flush(&mut self) -> io::Result<()> {
91         Ok(())
92     }
93 }
94 
95 impl io::Seek for &File {
seek(&mut self, pos: io::SeekFrom) -> io::Result<u64>96     fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
97         let (offset, whence) = match pos {
98             io::SeekFrom::Start(start) => (start as off_t, SEEK_SET),
99             io::SeekFrom::Current(current) => (current as off_t, SEEK_CUR),
100             io::SeekFrom::End(end) => (end as off_t, SEEK_END),
101         };
102 
103         match Sys::lseek(self.fd, offset, whence) {
104             -1 => Err(io::last_os_error()),
105             ok => Ok(ok as u64),
106         }
107     }
108 }
109 
110 impl io::Read for File {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>111     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
112         (&mut &*self).read(buf)
113     }
114 }
115 
116 impl io::Write for File {
write(&mut self, buf: &[u8]) -> io::Result<usize>117     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
118         (&mut &*self).write(buf)
119     }
120 
flush(&mut self) -> io::Result<()>121     fn flush(&mut self) -> io::Result<()> {
122         (&mut &*self).flush()
123     }
124 }
125 
126 impl io::Seek for File {
seek(&mut self, pos: io::SeekFrom) -> io::Result<u64>127     fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
128         (&mut &*self).seek(pos)
129     }
130 }
131 
132 impl Deref for File {
133     type Target = c_int;
134 
deref(&self) -> &Self::Target135     fn deref(&self) -> &Self::Target {
136         &self.fd
137     }
138 }
139 
140 impl Drop for File {
drop(&mut self)141     fn drop(&mut self) {
142         if !self.reference {
143             let _ = Sys::close(self.fd);
144         }
145     }
146 }
147