1#![allow(clippy::missing_panics_doc)]
3
4use std::fmt::{self, Debug, Formatter};
7use std::io::RawOsError;
8use std::marker::PhantomData;
9
10use libc::{EBADF, EDQUOT, EINTR, EINVAL, EIO, ENOLCK, ENOSPC, EROFS, EWOULDBLOCK, LOCK_EX, LOCK_SH, LOCK_UN, c_int, c_void};
11
12use super::{AccessMode, CloneError, CloseError, LockError, MetadataError, OpenOptions, Read, ReadWrite, SyncError, TryLockError, Write};
13use crate::collections::contiguous::Vector;
14use crate::fs::file::{CreateError, NoCreate, OpenError, TempError};
15use crate::fs::panic::{BadFdPanic, InvalidOpPanic, Panic, UnexpectedErrorPanic};
16use crate::fs::{Abs, Directory, Fd, Metadata, OwnedPath, Path, Rel};
17use crate::fs::error::{IOError, InterruptError, LockMemError, StorageExhaustedError, SyncUnsupportedError, WouldBlockError};
18use crate::util;
19
20pub(crate) const DEF_FILE_MODE: c_int = 0o666;
21
22pub struct File<Access: AccessMode = ReadWrite> {
26 pub(crate) _access: PhantomData<fn() -> Access>,
27 pub(crate) fd: Fd,
28}
29
30impl File {
31 pub fn options() -> OpenOptions<ReadWrite, NoCreate> {
32 OpenOptions::<ReadWrite, NoCreate>::new()
33 }
34}
35
36impl<A: AccessMode> File<A> {
37 pub fn metadata(&self) -> Result<Metadata, MetadataError> {
38 self.fd.metadata()
39 }
40
41 pub fn close(self) -> Result<(), CloseError> {
42 self.fd.close()
43 }
44
45 pub fn sync(&self) -> Result<(), SyncError> {
46 if unsafe { libc::fsync(*self.fd) } == -1 {
50 match util::fs::err_no() {
51 EBADF => BadFdPanic.panic(),
52 EINTR => Err(InterruptError)?,
53 EIO => Err(IOError)?,
54 EROFS | EINVAL => Err(SyncUnsupportedError)?,
55 ENOSPC | EDQUOT => Err(StorageExhaustedError)?,
56 e => UnexpectedErrorPanic(e).panic(),
57 }
58 }
59 Ok(())
60 }
61
62 pub fn try_clone(&self) -> Result<File, CloneError> {
67 self.fd.try_clone().map(|new_fd| File {
68 _access: PhantomData,
69 fd: new_fd,
70 })
71 }
72
73 pub(crate) fn flock_raw(&self, flags: c_int) -> Result<(), LockError> {
74 if unsafe { libc::flock(*self.fd, flags) } == -1 {
78 match util::fs::err_no() {
79 EBADF => BadFdPanic.panic(),
80 EINTR => Err(InterruptError)?,
81 EINVAL => InvalidOpPanic.panic(),
82 ENOLCK => Err(LockMemError)?,
83 e => UnexpectedErrorPanic(e).panic(),
85 }
86 }
87 Ok(())
88 }
89
90 pub fn lock(&self) -> Result<(), LockError> {
91 self.flock_raw(LOCK_EX)
92 }
93
94 pub fn lock_shared(&self) -> Result<(), LockError> {
95 self.flock_raw(LOCK_SH)
96 }
97
98 pub(crate) fn try_flock_raw(&self, flags: c_int) -> Result<(), TryLockError> {
99 if unsafe { libc::flock(*self.fd, flags | libc::LOCK_NB) } == -1 {
103 match util::fs::err_no() {
104 EBADF => BadFdPanic.panic(),
105 EINTR => Err(InterruptError)?,
106 EINVAL => InvalidOpPanic.panic(),
107 ENOLCK => Err(LockMemError)?,
108 EWOULDBLOCK => Err(WouldBlockError)?,
109 e => UnexpectedErrorPanic(e).panic(),
110 }
111 }
112 Ok(())
113 }
114
115 pub fn try_lock(&self) -> Result<(), TryLockError> {
116 self.try_flock_raw(LOCK_EX)
117 }
118
119 pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
120 self.try_flock_raw(LOCK_SH)
121 }
122
123 pub fn unlock(&self) -> Result<(), LockError> {
124 self.flock_raw(LOCK_UN)
125 }
126}
127
128impl File<ReadWrite> {
129 pub fn open<P: Into<OwnedPath<Abs>>>(
130 file_path: P,
131 ) -> Result<File<ReadWrite>, OpenError> {
132 File::options()
133 .open(file_path)
134 }
135
136 pub fn create<P: Into<OwnedPath<Abs>>>(
137 file_path: P,
138 file_mode: u16,
139 ) -> Result<File<ReadWrite>, CreateError> {
140 File::options()
141 .create()
142 .mode(file_mode)
143 .open(file_path)
144 }
145
146 pub fn open_or_create<P: Into<OwnedPath<Abs>>>(
147 file_path: P,
148 file_mode: u16,
149 ) -> Result<File<ReadWrite>, OpenError> {
150 File::options()
151 .create_if_missing()
152 .mode(file_mode)
153 .open(file_path)
154 }
155
156 pub fn open_rel<P: Into<OwnedPath<Rel>>>(
157 relative_to: &Directory,
158 file_path: P
159 ) -> Result<File<ReadWrite>, OpenError> {
160 File::options()
161 .open_rel(relative_to, file_path)
162 }
163
164 pub fn create_rel<P: Into<OwnedPath<Rel>>>(
165 relative_to: &Directory,
166 file_path: P,
167 file_mode: u16,
168 ) -> Result<File<ReadWrite>, CreateError> {
169 File::options()
170 .create()
171 .mode(file_mode)
172 .open_rel(relative_to, file_path)
173 }
174
175 pub fn open_or_create_rel<P: Into<OwnedPath<Rel>>>(
176 relative_to: &Directory,
177 file_path: P,
178 file_mode: u16,
179 ) -> Result<File<ReadWrite>, OpenError> {
180 File::options()
181 .create_if_missing()
182 .mode(file_mode)
183 .open_rel(relative_to, file_path)
184 }
185
186 pub fn create_temp() -> Result<File<ReadWrite>, TempError> {
187 File::<ReadWrite>::options()
188 .create_temp()
189 .mode(0o700)
190 .open(unsafe { Path::<Abs>::from_unchecked("/tmp") })
191 }
192}
193
194
195impl<A: Read> File<A> {
196 pub(crate) fn read_raw(&self, buf: *mut c_void, size: usize) -> Result<usize, RawOsError> {
197 match unsafe { libc::read(*self.fd, buf, size) } {
203 -1 => Err(util::fs::err_no()),
204 count => Ok(count as usize),
205 }
206 }
207
208 pub fn read(&self, buf: &mut [u8]) -> Result<usize, RawOsError> {
209 self.read_raw(buf.as_mut_ptr().cast(), buf.len())
210 }
211
212 pub fn read_all_vec(&self) -> Result<Vector<u8>, RawOsError> {
213 let size = self.metadata().unwrap().size as usize; let buf: Vector<u8> = Vector::with_cap(size);
216 let (ptr, len, cap) = buf.into_parts();
217
218 match self.read_raw(unsafe { ptr.as_ptr().add(len).cast() }, cap) {
219 Err(err) => {
220 unsafe { drop(Vector::from_parts(ptr, len, cap)); }
221 Err(err)
222 },
223 Ok(count) if size > count => {
::core::panicking::panic_fmt(format_args!("not yet implemented: {0}",
format_args!("Repeat until all bytes are read!")));
}todo!("Repeat until all bytes are read!"), Ok(count) => unsafe { Ok(Vector::from_parts(ptr, len + count, cap)) },
225 }
226 }
227
228 pub fn read_all_string(&self) -> Result<String, RawOsError> {
229 Ok(String::from_utf8(self.read_all_vec()?.into()).unwrap())
230 }
231}
232
233impl<A: Write> File<A> {
234 pub(crate) fn write_raw(&self, buf: *const c_void, size: usize) -> Result<usize, RawOsError> {
235 match unsafe { libc::write(*self.fd, buf, size) } {
241 -1 => Err(util::fs::err_no()),
242 count => Ok(count as usize),
243 }
244 }
245
246 pub fn write(&self, buf: &[u8]) -> Result<usize, RawOsError> {
247 self.write_raw(buf.as_ptr().cast(), buf.len())
248 }
249}
250
251impl<A: AccessMode> Debug for File<A> {
252 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
253 f.debug_struct("File")
254 .field("<access>", &util::fmt::raw_type_name::<A>())
255 .field("fd", &self.fd).finish()
256 }
257}