Skip to main content

relibc/
fs.rs

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