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