1use std::sync::Arc;
4
5use atomic_refcell::AtomicRefCell;
6use linux_api::fcntl::{DescriptorFlags, OFlag};
7use linux_api::ioctls::IoctlRequest;
8use shadow_shim_helper_rs::syscall_types::ForeignPtr;
9
10use crate::core::worker;
11use crate::cshadow as c;
12use crate::host::descriptor::listener::{StateListenHandle, StateListenerFilter};
13use crate::host::descriptor::socket::{Socket, SocketRef, SocketRefMut};
14use crate::host::host::Host;
15use crate::host::memory_manager::MemoryManager;
16use crate::host::syscall::io::IoVec;
17use crate::host::syscall::types::{SyscallError, SyscallResult};
18use crate::utility::callback_queue::CallbackQueue;
19use crate::utility::{HostTreePointer, IsSend, IsSync, ObjectCounter};
20
21pub mod descriptor_table;
22pub mod epoll;
23pub mod eventfd;
24pub mod listener;
25pub mod pipe;
26pub mod shared_buf;
27pub mod socket;
28pub mod timerfd;
29
30bitflags::bitflags! {
31 #[derive(Copy, Clone, Debug)]
38 pub struct FileStatus: i32 {
39 const NONBLOCK = OFlag::O_NONBLOCK.bits();
40 const APPEND = OFlag::O_APPEND.bits();
41 const ASYNC = OFlag::O_ASYNC.bits();
42 const DIRECT = OFlag::O_DIRECT.bits();
43 const NOATIME = OFlag::O_NOATIME.bits();
44 }
45}
46
47impl FileStatus {
48 pub fn as_o_flags(&self) -> OFlag {
49 OFlag::from_bits(self.bits()).unwrap()
50 }
51
52 pub fn from_o_flags(flags: OFlag) -> (Self, OFlag) {
54 let status = Self::from_bits_truncate(flags.bits());
55 let remaining = flags.bits() & !status.bits();
56 (status, OFlag::from_bits(remaining).unwrap())
57 }
58}
59
60bitflags::bitflags! {
61 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
67 pub struct FileMode: u32 {
68 const READ = 0b00000001;
69 const WRITE = 0b00000010;
70 }
71}
72
73impl FileMode {
74 pub fn as_o_flags(&self) -> OFlag {
75 const READ_AND_WRITE: FileMode = FileMode::READ.union(FileMode::WRITE);
76 const EMPTY: FileMode = FileMode::empty();
77
78 match *self {
80 READ_AND_WRITE => OFlag::O_RDWR,
81 Self::READ => OFlag::O_RDONLY,
82 Self::WRITE => OFlag::O_WRONLY,
83 EMPTY => OFlag::O_PATH,
85 _ => panic!("Invalid file mode flags"),
86 }
87 }
88
89 #[allow(clippy::result_unit_err)]
92 pub fn from_o_flags(flags: OFlag) -> Result<(Self, OFlag), ()> {
93 let mode = flags & (OFlag::O_ACCMODE | OFlag::O_PATH);
96 let remaining = flags - (OFlag::O_ACCMODE | OFlag::O_PATH);
97
98 let mode = match mode {
100 OFlag::O_RDONLY => FileMode::READ,
101 OFlag::O_WRONLY => FileMode::WRITE,
102 OFlag::O_RDWR => FileMode::READ | FileMode::WRITE,
103 OFlag::O_PATH => FileMode::empty(),
104 _ => return Err(()),
105 };
106
107 Ok((mode, remaining))
108 }
109}
110
111bitflags::bitflags! {
112 #[derive(Default, Copy, Clone, Debug)]
116 #[repr(transparent)]
117 pub struct FileState: u16 {
118 #[deprecated(note = "use `FileState::empty()`")]
120 const NONE = 0;
121 const ACTIVE = 1 << 0;
126 const READABLE = 1 << 1;
128 const WRITABLE = 1 << 2;
130 const CLOSED = 1 << 3;
132 const FUTEX_WAKEUP = 1 << 4;
134 const CHILD_EVENT = 1 << 5;
136 const SOCKET_ALLOWING_CONNECT = 1 << 6;
139 const RDHUP = 1 << 7;
142 }
143}
144
145bitflags::bitflags! {
146 #[derive(Default, Copy, Clone, Debug)]
148 #[repr(transparent)]
149 pub struct FileSignals: u32 {
150 const READ_BUFFER_GREW = 1 << 0;
152 }
153}
154
155#[derive(Clone)]
157pub enum File {
158 Pipe(Arc<AtomicRefCell<pipe::Pipe>>),
159 EventFd(Arc<AtomicRefCell<eventfd::EventFd>>),
160 Socket(Socket),
161 TimerFd(Arc<AtomicRefCell<timerfd::TimerFd>>),
162 Epoll(Arc<AtomicRefCell<epoll::Epoll>>),
163}
164
165impl IsSend for File {}
167impl IsSync for File {}
168
169impl File {
170 pub fn borrow(&self) -> FileRef {
171 match self {
172 Self::Pipe(f) => FileRef::Pipe(f.borrow()),
173 Self::EventFd(f) => FileRef::EventFd(f.borrow()),
174 Self::Socket(f) => FileRef::Socket(f.borrow()),
175 Self::TimerFd(f) => FileRef::TimerFd(f.borrow()),
176 Self::Epoll(f) => FileRef::Epoll(f.borrow()),
177 }
178 }
179
180 pub fn try_borrow(&self) -> Result<FileRef, atomic_refcell::BorrowError> {
181 Ok(match self {
182 Self::Pipe(f) => FileRef::Pipe(f.try_borrow()?),
183 Self::EventFd(f) => FileRef::EventFd(f.try_borrow()?),
184 Self::Socket(f) => FileRef::Socket(f.try_borrow()?),
185 Self::TimerFd(f) => FileRef::TimerFd(f.try_borrow()?),
186 Self::Epoll(f) => FileRef::Epoll(f.try_borrow()?),
187 })
188 }
189
190 pub fn borrow_mut(&self) -> FileRefMut {
191 match self {
192 Self::Pipe(f) => FileRefMut::Pipe(f.borrow_mut()),
193 Self::EventFd(f) => FileRefMut::EventFd(f.borrow_mut()),
194 Self::Socket(f) => FileRefMut::Socket(f.borrow_mut()),
195 Self::TimerFd(f) => FileRefMut::TimerFd(f.borrow_mut()),
196 Self::Epoll(f) => FileRefMut::Epoll(f.borrow_mut()),
197 }
198 }
199
200 pub fn try_borrow_mut(&self) -> Result<FileRefMut, atomic_refcell::BorrowMutError> {
201 Ok(match self {
202 Self::Pipe(f) => FileRefMut::Pipe(f.try_borrow_mut()?),
203 Self::EventFd(f) => FileRefMut::EventFd(f.try_borrow_mut()?),
204 Self::Socket(f) => FileRefMut::Socket(f.try_borrow_mut()?),
205 Self::TimerFd(f) => FileRefMut::TimerFd(f.try_borrow_mut()?),
206 Self::Epoll(f) => FileRefMut::Epoll(f.try_borrow_mut()?),
207 })
208 }
209
210 pub fn canonical_handle(&self) -> usize {
211 match self {
212 Self::Pipe(f) => Arc::as_ptr(f) as usize,
213 Self::EventFd(f) => Arc::as_ptr(f) as usize,
214 Self::Socket(f) => f.canonical_handle(),
215 Self::TimerFd(f) => Arc::as_ptr(f) as usize,
216 Self::Epoll(f) => Arc::as_ptr(f) as usize,
217 }
218 }
219}
220
221impl std::fmt::Debug for File {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 match self {
224 Self::Pipe(_) => write!(f, "Pipe")?,
225 Self::EventFd(_) => write!(f, "EventFd")?,
226 Self::Socket(_) => write!(f, "Socket")?,
227 Self::TimerFd(_) => write!(f, "TimerFd")?,
228 Self::Epoll(_) => write!(f, "Epoll")?,
229 }
230
231 if let Ok(file) = self.try_borrow() {
232 let state = file.state();
233 let status = file.status();
234 write!(f, "(state: {state:?}, status: {status:?})")
235 } else {
236 write!(f, "(already borrowed)")
237 }
238 }
239}
240
241pub enum FileRef<'a> {
243 Pipe(atomic_refcell::AtomicRef<'a, pipe::Pipe>),
244 EventFd(atomic_refcell::AtomicRef<'a, eventfd::EventFd>),
245 Socket(SocketRef<'a>),
246 TimerFd(atomic_refcell::AtomicRef<'a, timerfd::TimerFd>),
247 Epoll(atomic_refcell::AtomicRef<'a, epoll::Epoll>),
248}
249
250pub enum FileRefMut<'a> {
253 Pipe(atomic_refcell::AtomicRefMut<'a, pipe::Pipe>),
254 EventFd(atomic_refcell::AtomicRefMut<'a, eventfd::EventFd>),
255 Socket(SocketRefMut<'a>),
256 TimerFd(atomic_refcell::AtomicRefMut<'a, timerfd::TimerFd>),
257 Epoll(atomic_refcell::AtomicRefMut<'a, epoll::Epoll>),
258}
259
260impl FileRef<'_> {
261 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
262 pub fn state(&self) -> FileState
263 );
264 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
265 pub fn mode(&self) -> FileMode
266 );
267 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
268 pub fn status(&self) -> FileStatus
269 );
270 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
271 pub fn stat(&self) -> Result<linux_api::stat::stat, SyscallError>
272 );
273 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
274 pub fn has_open_file(&self) -> bool
275 );
276 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
277 pub fn supports_sa_restart(&self) -> bool
278 );
279}
280
281impl FileRefMut<'_> {
282 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
283 pub fn state(&self) -> FileState
284 );
285 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
286 pub fn mode(&self) -> FileMode
287 );
288 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
289 pub fn status(&self) -> FileStatus
290 );
291 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
292 pub fn stat(&self) -> Result<linux_api::stat::stat, SyscallError>
293 );
294 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
295 pub fn has_open_file(&self) -> bool
296 );
297 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
298 pub fn supports_sa_restart(&self) -> bool
299 );
300 enum_passthrough!(self, (val), Pipe, EventFd, Socket, TimerFd, Epoll;
301 pub fn set_has_open_file(&mut self, val: bool)
302 );
303 enum_passthrough!(self, (cb_queue), Pipe, EventFd, Socket, TimerFd, Epoll;
304 pub fn close(&mut self, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError>
305 );
306 enum_passthrough!(self, (status), Pipe, EventFd, Socket, TimerFd, Epoll;
307 pub fn set_status(&mut self, status: FileStatus)
308 );
309 enum_passthrough!(self, (request, arg_ptr, memory_manager), Pipe, EventFd, Socket, TimerFd, Epoll;
310 pub fn ioctl(&mut self, request: IoctlRequest, arg_ptr: ForeignPtr<()>, memory_manager: &mut MemoryManager) -> SyscallResult
311 );
312 enum_passthrough!(self, (monitoring_state, monitoring_signals, filter, notify_fn), Pipe, EventFd, Socket, TimerFd, Epoll;
313 pub fn add_listener(
314 &mut self,
315 monitoring_state: FileState,
316 monitoring_signals: FileSignals,
317 filter: StateListenerFilter,
318 notify_fn: impl Fn(FileState, FileState, FileSignals, &mut CallbackQueue) + Send + Sync + 'static,
319 ) -> StateListenHandle
320 );
321 enum_passthrough!(self, (ptr), Pipe, EventFd, Socket, TimerFd, Epoll;
322 pub fn add_legacy_listener(&mut self, ptr: HostTreePointer<c::StatusListener>)
323 );
324 enum_passthrough!(self, (ptr), Pipe, EventFd, Socket, TimerFd, Epoll;
325 pub fn remove_legacy_listener(&mut self, ptr: *mut c::StatusListener)
326 );
327 enum_passthrough!(self, (iovs, offset, flags, mem, cb_queue), Pipe, EventFd, Socket, TimerFd, Epoll;
328 pub fn readv(&mut self, iovs: &[IoVec], offset: Option<libc::off_t>, flags: libc::c_int,
329 mem: &mut MemoryManager, cb_queue: &mut CallbackQueue) -> Result<libc::ssize_t, SyscallError>
330 );
331 enum_passthrough!(self, (iovs, offset, flags, mem, cb_queue), Pipe, EventFd, Socket, TimerFd, Epoll;
332 pub fn writev(&mut self, iovs: &[IoVec], offset: Option<libc::off_t>, flags: libc::c_int,
333 mem: &mut MemoryManager, cb_queue: &mut CallbackQueue) -> Result<libc::ssize_t, SyscallError>
334 );
335}
336
337impl std::fmt::Debug for FileRef<'_> {
338 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
339 match self {
340 Self::Pipe(_) => write!(f, "Pipe")?,
341 Self::EventFd(_) => write!(f, "EventFd")?,
342 Self::Socket(_) => write!(f, "Socket")?,
343 Self::TimerFd(_) => write!(f, "TimerFd")?,
344 Self::Epoll(_) => write!(f, "Epoll")?,
345 }
346
347 let state = self.state();
348 let status = self.status();
349 write!(f, "(state: {state:?}, status: {status:?})")
350 }
351}
352
353impl std::fmt::Debug for FileRefMut<'_> {
354 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
355 match self {
356 Self::Pipe(_) => write!(f, "Pipe")?,
357 Self::EventFd(_) => write!(f, "EventFd")?,
358 Self::Socket(_) => write!(f, "Socket")?,
359 Self::TimerFd(_) => write!(f, "TimerFd")?,
360 Self::Epoll(_) => write!(f, "Epoll")?,
361 }
362
363 let state = self.state();
364 let status = self.status();
365 write!(f, "(state: {state:?}, status: {status:?})")
366 }
367}
368
369#[derive(Clone, Debug)]
384pub struct OpenFile {
385 inner: Arc<OpenFileInner>,
386 _counter: ObjectCounter,
387}
388
389impl IsSend for OpenFile {}
391impl IsSync for OpenFile {}
392
393impl OpenFile {
394 pub fn new(file: File) -> Self {
395 {
396 let mut file = file.borrow_mut();
397
398 if file.state().contains(FileState::CLOSED) {
399 debug_panic!("Creating an `OpenFile` object for a closed file");
401 }
402
403 if file.has_open_file() {
404 debug_panic!(
406 "Creating an `OpenFile` object for a file that already has an `OpenFile` object"
407 );
408 }
409
410 file.set_has_open_file(true);
411 }
412
413 Self {
414 inner: Arc::new(OpenFileInner::new(file)),
415 _counter: ObjectCounter::new("OpenFile"),
416 }
417 }
418
419 pub fn inner_file(&self) -> &File {
420 self.inner.file.as_ref().unwrap()
421 }
422
423 pub fn close(self, cb_queue: &mut CallbackQueue) -> Option<Result<(), SyscallError>> {
427 let OpenFile { inner, _counter } = self;
428
429 Arc::into_inner(inner).map(|inner| inner.close(cb_queue))
431 }
432}
433
434#[derive(Clone, Debug)]
435struct OpenFileInner {
436 file: Option<File>,
437 _counter: ObjectCounter,
438}
439
440impl OpenFileInner {
441 pub fn new(file: File) -> Self {
442 Self {
443 file: Some(file),
444 _counter: ObjectCounter::new("OpenFileInner"),
445 }
446 }
447
448 pub fn close(mut self, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError> {
449 self.close_helper(cb_queue)
450 }
451
452 fn close_helper(&mut self, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError> {
453 if let Some(file) = self.file.take() {
454 file.borrow_mut().close(cb_queue)?;
455 }
456 Ok(())
457 }
458}
459
460impl std::ops::Drop for OpenFileInner {
461 fn drop(&mut self) {
462 let _ = CallbackQueue::queue_and_run_with_legacy(|cb_queue| self.close_helper(cb_queue));
464 }
465}
466
467#[derive(Debug, Clone)]
470pub struct Descriptor {
471 file: CompatFile,
473 flags: DescriptorFlags,
475 _counter: ObjectCounter,
476}
477
478impl IsSend for Descriptor {}
480impl IsSync for Descriptor {}
481
482impl Descriptor {
483 pub fn new(file: CompatFile) -> Self {
484 Self {
485 file,
486 flags: DescriptorFlags::empty(),
487 _counter: ObjectCounter::new("Descriptor"),
488 }
489 }
490
491 pub fn file(&self) -> &CompatFile {
492 &self.file
493 }
494
495 pub fn flags(&self) -> DescriptorFlags {
496 self.flags
497 }
498
499 pub fn set_flags(&mut self, flags: DescriptorFlags) {
500 self.flags = flags;
501 }
502
503 pub fn into_file(self) -> CompatFile {
504 self.file
505 }
506
507 pub fn close(
509 self,
510 host: &Host,
511 cb_queue: &mut CallbackQueue,
512 ) -> Option<Result<(), SyscallError>> {
513 self.file.close(host, cb_queue)
514 }
515
516 pub fn dup(&self, flags: DescriptorFlags) -> Self {
520 Self {
521 file: self.file.clone(),
522 flags,
523 _counter: ObjectCounter::new("Descriptor"),
524 }
525 }
526
527 pub fn into_raw(descriptor: Box<Self>) -> *mut Self {
528 Box::into_raw(descriptor)
529 }
530
531 pub fn from_raw(descriptor: *mut Self) -> Option<Box<Self>> {
532 if descriptor.is_null() {
533 return None;
534 }
535
536 unsafe { Some(Box::from_raw(descriptor)) }
537 }
538
539 pub unsafe fn from_legacy_file(
551 legacy_file: *mut c::LegacyFile,
552 descriptor_flags: OFlag,
553 ) -> Descriptor {
554 assert!(!legacy_file.is_null());
555
556 assert_ne!(
558 unsafe { c::legacyfile_getType(legacy_file) },
559 c::_LegacyFileType_DT_TCPSOCKET,
560 );
561
562 let mut descriptor = Descriptor::new(CompatFile::Legacy(LegacyFileCounter::new(
563 CountedLegacyFileRef::new(HostTreePointer::new(legacy_file)),
564 )));
565
566 let (descriptor_flags, remaining) = DescriptorFlags::from_o_flags(descriptor_flags);
567 assert!(remaining.is_empty());
568 descriptor.set_flags(descriptor_flags);
569 descriptor
570 }
571}
572
573#[derive(Debug)]
576pub struct CountedLegacyFileRef(HostTreePointer<c::LegacyFile>);
577
578impl CountedLegacyFileRef {
579 pub fn new(ptr: HostTreePointer<c::LegacyFile>) -> Self {
582 Self(ptr)
583 }
584
585 pub unsafe fn ptr(&self) -> *mut c::LegacyFile {
589 unsafe { self.0.ptr() }
590 }
591}
592
593impl std::clone::Clone for CountedLegacyFileRef {
594 fn clone(&self) -> Self {
595 unsafe { c::legacyfile_ref(self.0.ptr() as *mut core::ffi::c_void) };
597 Self(self.0)
598 }
599}
600
601impl Drop for CountedLegacyFileRef {
602 fn drop(&mut self) {
603 unsafe { c::legacyfile_unref(self.0.ptr() as *mut core::ffi::c_void) };
605 }
606}
607
608#[derive(Clone, Debug)]
614pub struct LegacyFileCounter {
615 file: Option<CountedLegacyFileRef>,
616 open_count: Arc<()>,
618}
619
620impl LegacyFileCounter {
621 pub fn new(file: CountedLegacyFileRef) -> Self {
622 Self {
623 file: Some(file),
624 open_count: Arc::new(()),
625 }
626 }
627
628 pub fn ptr(&self) -> *mut c::LegacyFile {
629 unsafe { self.file.as_ref().unwrap().ptr() }
630 }
631
632 fn close_helper(&mut self, host: &Host) {
634 if Arc::<()>::strong_count(&self.open_count) == 1 {
637 if let Some(file) = self.file.take() {
638 unsafe { c::legacyfile_close(file.ptr(), host) }
639 }
640 }
641 }
642
643 pub fn close(mut self, host: &Host) {
646 self.close_helper(host);
647 }
648}
649
650impl std::ops::Drop for LegacyFileCounter {
651 fn drop(&mut self) {
652 worker::Worker::with_active_host(|host| self.close_helper(host)).unwrap();
653 }
654}
655
656#[derive(Clone, Debug)]
658pub enum CompatFile {
659 New(OpenFile),
660 Legacy(LegacyFileCounter),
661}
662
663impl CompatFile {
664 pub fn close(
666 self,
667 host: &Host,
668 cb_queue: &mut CallbackQueue,
669 ) -> Option<Result<(), SyscallError>> {
670 match self {
671 Self::New(file) => file.close(cb_queue),
672 Self::Legacy(file) => {
673 file.close(host);
674 Some(Ok(()))
675 }
676 }
677 }
678}
679
680mod export {
681 use super::*;
682
683 use crate::host::descriptor::socket::inet::InetSocket;
684 use crate::host::descriptor::socket::inet::legacy_tcp::LegacyTcpSocket;
685
686 #[unsafe(no_mangle)]
694 pub unsafe extern "C-unwind" fn descriptor_fromLegacyFile(
695 legacy_file: *mut c::LegacyFile,
696 descriptor_flags: libc::c_int,
697 ) -> *mut Descriptor {
698 let descriptor_flags = OFlag::from_bits(descriptor_flags).unwrap();
699 let descriptor = unsafe { Descriptor::from_legacy_file(legacy_file, descriptor_flags) };
700 Descriptor::into_raw(Box::new(descriptor))
701 }
702
703 #[unsafe(no_mangle)]
708 pub unsafe extern "C-unwind" fn descriptor_fromLegacyTcp(
709 legacy_tcp: *mut c::TCP,
710 descriptor_flags: libc::c_int,
711 ) -> *mut Descriptor {
712 assert!(!legacy_tcp.is_null());
713
714 let tcp = unsafe { LegacyTcpSocket::new_from_legacy(legacy_tcp) };
715 let mut descriptor = Descriptor::new(CompatFile::New(OpenFile::new(File::Socket(
716 Socket::Inet(InetSocket::LegacyTcp(tcp)),
717 ))));
718
719 let descriptor_flags = OFlag::from_bits(descriptor_flags).unwrap();
720 let (descriptor_flags, remaining) = DescriptorFlags::from_o_flags(descriptor_flags);
721 assert!(remaining.is_empty());
722 descriptor.set_flags(descriptor_flags);
723
724 Descriptor::into_raw(Box::new(descriptor))
725 }
726
727 #[unsafe(no_mangle)]
731 pub extern "C-unwind" fn descriptor_asLegacyFile(
732 descriptor: *const Descriptor,
733 ) -> *mut c::LegacyFile {
734 assert!(!descriptor.is_null());
735
736 let descriptor = unsafe { &*descriptor };
737
738 if let CompatFile::Legacy(d) = descriptor.file() {
739 d.ptr()
740 } else {
741 std::ptr::null_mut()
742 }
743 }
744
745 #[unsafe(no_mangle)]
749 pub extern "C-unwind" fn descriptor_borrowOpenFile(
750 descriptor: *const Descriptor,
751 ) -> *const OpenFile {
752 assert!(!descriptor.is_null());
753
754 let descriptor = unsafe { &*descriptor };
755
756 match descriptor.file() {
757 CompatFile::Legacy(_) => std::ptr::null_mut(),
758 CompatFile::New(d) => d,
759 }
760 }
761
762 #[unsafe(no_mangle)]
767 pub extern "C-unwind" fn descriptor_newRefOpenFile(
768 descriptor: *const Descriptor,
769 ) -> *const OpenFile {
770 assert!(!descriptor.is_null());
771
772 let descriptor = unsafe { &*descriptor };
773
774 match descriptor.file() {
775 CompatFile::Legacy(_) => std::ptr::null_mut(),
776 CompatFile::New(d) => Box::into_raw(Box::new(d.clone())),
777 }
778 }
779
780 #[unsafe(no_mangle)]
782 pub extern "C-unwind" fn descriptor_setFlags(descriptor: *mut Descriptor, flags: libc::c_int) {
783 assert!(!descriptor.is_null());
784
785 let descriptor = unsafe { &mut *descriptor };
786 let flags = OFlag::from_bits(flags).unwrap();
787 let (flags, remaining_flags) = DescriptorFlags::from_o_flags(flags);
788 assert!(remaining_flags.is_empty());
789
790 descriptor.set_flags(flags);
791 }
792
793 #[unsafe(no_mangle)]
796 pub extern "C-unwind" fn openfile_drop(file: *const OpenFile) {
797 assert!(!file.is_null());
798
799 drop(unsafe { Box::from_raw(file.cast_mut()) });
800 }
801
802 #[unsafe(no_mangle)]
804 pub extern "C-unwind" fn openfile_getStatus(file: *const OpenFile) -> FileState {
805 assert!(!file.is_null());
806
807 let file = unsafe { &*file };
808
809 file.inner_file().borrow().state()
810 }
811
812 #[unsafe(no_mangle)]
816 pub unsafe extern "C-unwind" fn openfile_addListener(
817 file: *const OpenFile,
818 listener: *mut c::StatusListener,
819 ) {
820 assert!(!file.is_null());
821 assert!(!listener.is_null());
822
823 let file = unsafe { &*file };
824
825 file.inner_file()
826 .borrow_mut()
827 .add_legacy_listener(HostTreePointer::new(listener));
828 }
829
830 #[unsafe(no_mangle)]
832 pub extern "C-unwind" fn openfile_removeListener(
833 file: *const OpenFile,
834 listener: *mut c::StatusListener,
835 ) {
836 assert!(!file.is_null());
837 assert!(!listener.is_null());
838
839 let file = unsafe { &*file };
840
841 file.inner_file()
842 .borrow_mut()
843 .remove_legacy_listener(listener);
844 }
845
846 #[unsafe(no_mangle)]
849 pub extern "C-unwind" fn openfile_getCanonicalHandle(file: *const OpenFile) -> libc::uintptr_t {
850 assert!(!file.is_null());
851
852 let file = unsafe { &*file };
853
854 file.inner_file().canonical_handle()
855 }
856
857 #[unsafe(no_mangle)]
861 pub extern "C-unwind" fn descriptor_newRefFile(descriptor: *const Descriptor) -> *const File {
862 assert!(!descriptor.is_null());
863
864 let descriptor = unsafe { &*descriptor };
865
866 match descriptor.file() {
867 CompatFile::Legacy(_) => std::ptr::null_mut(),
868 CompatFile::New(d) => Box::into_raw(Box::new(d.inner_file().clone())),
869 }
870 }
871
872 #[unsafe(no_mangle)]
875 pub extern "C-unwind" fn file_drop(file: *const File) {
876 assert!(!file.is_null());
877
878 drop(unsafe { Box::from_raw(file.cast_mut()) });
879 }
880
881 #[unsafe(no_mangle)]
885 pub extern "C-unwind" fn file_cloneRef(file: *const File) -> *const File {
886 let file = unsafe { file.as_ref() }.unwrap();
887 Box::into_raw(Box::new(file.clone()))
888 }
889
890 #[unsafe(no_mangle)]
892 pub extern "C-unwind" fn file_getStatus(file: *const File) -> FileState {
893 assert!(!file.is_null());
894
895 let file = unsafe { &*file };
896
897 file.borrow().state()
898 }
899
900 #[unsafe(no_mangle)]
904 pub unsafe extern "C-unwind" fn file_addListener(
905 file: *const File,
906 listener: *mut c::StatusListener,
907 ) {
908 assert!(!file.is_null());
909 assert!(!listener.is_null());
910
911 let file = unsafe { &*file };
912
913 file.borrow_mut()
914 .add_legacy_listener(HostTreePointer::new(listener));
915 }
916
917 #[unsafe(no_mangle)]
919 pub extern "C-unwind" fn file_removeListener(
920 file: *const File,
921 listener: *mut c::StatusListener,
922 ) {
923 assert!(!file.is_null());
924 assert!(!listener.is_null());
925
926 let file = unsafe { &*file };
927
928 file.borrow_mut().remove_legacy_listener(listener);
929 }
930
931 #[unsafe(no_mangle)]
934 pub extern "C-unwind" fn file_getCanonicalHandle(file: *const File) -> libc::uintptr_t {
935 assert!(!file.is_null());
936
937 let file = unsafe { &*file };
938
939 file.canonical_handle()
940 }
941}
942
943#[cfg(test)]
944mod tests {
945 use super::*;
946 use crate::host::syscall::Trigger;
947 use crate::host::syscall::condition::SyscallCondition;
948 use crate::host::syscall::types::{
949 Blocked, Failed, SyscallError, SyscallReturn, SyscallReturnBlocked, SyscallReturnDone,
950 };
951
952 #[test]
953 #[cfg_attr(miri, ignore)]
955 fn test_syscallresult_roundtrip() {
956 for val in vec![
957 Ok(1.into()),
958 Err(linux_api::errno::Errno::EPERM.into()),
959 Err(SyscallError::Failed(Failed {
960 errno: linux_api::errno::Errno::EINTR,
961 restartable: true,
962 })),
963 Err(SyscallError::Failed(Failed {
964 errno: linux_api::errno::Errno::EINTR,
965 restartable: false,
966 })),
967 Err(SyscallError::Blocked(Blocked {
968 condition: SyscallCondition::new(Trigger::from(c::Trigger {
969 type_: 1,
970 object: c::TriggerObject {
971 as_pointer: std::ptr::null_mut(),
972 },
973 state: FileState::CLOSED,
974 })),
975 restartable: true,
976 })),
977 ]
978 .drain(..)
979 {
980 let orig_debug = format!("{:?}", &val);
984 let roundtripped = SyscallResult::from(SyscallReturn::from(val));
985 let roundtripped_debug = format!("{:?}", roundtripped);
986 assert_eq!(orig_debug, roundtripped_debug);
987 }
988 }
989
990 #[test]
991 #[cfg_attr(miri, ignore)]
993 fn test_syscallreturn_roundtrip() {
994 let condition = SyscallCondition::new(Trigger::from(c::Trigger {
995 type_: 1,
996 object: c::TriggerObject {
997 as_pointer: std::ptr::null_mut(),
998 },
999 state: FileState::CLOSED,
1000 }));
1001 for val in vec![
1002 SyscallReturn::Done(SyscallReturnDone {
1003 retval: 1.into(),
1004 restartable: false,
1005 }),
1006 SyscallReturn::Block(SyscallReturnBlocked {
1007 cond: condition.into_inner(),
1008 restartable: true,
1009 }),
1010 SyscallReturn::Native,
1011 ]
1012 .drain(..)
1013 {
1014 let orig_debug = format!("{:?}", &val);
1019 let roundtripped = SyscallReturn::from(SyscallResult::from(val));
1020 let roundtripped_debug = format!("{:?}", roundtripped);
1021 assert_eq!(orig_debug, roundtripped_debug);
1022 }
1023 }
1024
1025 #[test]
1026 fn test_file_mode_o_flags() {
1027 assert_eq!(
1029 FileMode::from_o_flags(OFlag::O_PATH),
1030 Ok((FileMode::empty(), OFlag::empty()))
1031 );
1032 assert_eq!(
1033 FileMode::from_o_flags(OFlag::O_WRONLY),
1034 Ok((FileMode::WRITE, OFlag::empty()))
1035 );
1036 assert_eq!(
1037 FileMode::from_o_flags(OFlag::O_RDWR),
1038 Ok((FileMode::READ | FileMode::WRITE, OFlag::empty()))
1039 );
1040 assert_eq!(
1041 FileMode::from_o_flags(OFlag::O_RDONLY),
1042 Ok((FileMode::READ, OFlag::empty()))
1043 );
1044 assert_eq!(
1045 FileMode::from_o_flags(OFlag::empty()),
1046 Ok((FileMode::READ, OFlag::empty()))
1047 );
1048 assert_eq!(
1049 FileMode::from_o_flags(OFlag::O_RDWR | OFlag::O_WRONLY),
1050 Err(())
1051 );
1052 assert_eq!(
1053 FileMode::from_o_flags(OFlag::O_RDWR | OFlag::O_RDONLY),
1054 Ok((FileMode::READ | FileMode::WRITE, OFlag::empty()))
1055 );
1056 assert_eq!(
1057 FileMode::from_o_flags(OFlag::O_WRONLY | OFlag::O_RDONLY),
1058 Ok((FileMode::WRITE, OFlag::empty()))
1059 );
1060 assert_eq!(
1061 FileMode::from_o_flags(OFlag::O_PATH | OFlag::O_WRONLY),
1062 Err(())
1063 );
1064 assert_eq!(
1065 FileMode::from_o_flags(OFlag::O_WRONLY | OFlag::O_CLOEXEC),
1066 Ok((FileMode::WRITE, OFlag::O_CLOEXEC))
1067 );
1068
1069 assert_eq!(FileMode::as_o_flags(&FileMode::empty()), OFlag::O_PATH);
1071 assert_eq!(FileMode::as_o_flags(&FileMode::READ), OFlag::O_RDONLY);
1072 assert_eq!(FileMode::as_o_flags(&FileMode::WRITE), OFlag::O_WRONLY);
1073 assert_eq!(
1074 FileMode::as_o_flags(&(FileMode::READ | FileMode::WRITE)),
1075 OFlag::O_RDWR
1076 );
1077 }
1078}