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)]
122 #[repr(transparent)]
123 pub struct FileState: u16 {
124 #[deprecated(note = "use `FileState::empty()`")]
126 const NONE = 0;
127 const ACTIVE = 1 << 0;
132 const READABLE = 1 << 1;
134 const WRITABLE = 1 << 2;
136 const CLOSED = 1 << 3;
138 const FUTEX_WAKEUP = 1 << 4;
140 const CHILD_EVENT = 1 << 5;
142 const SOCKET_ALLOWING_CONNECT = 1 << 6;
145 const RDHUP = 1 << 7;
148 }
149}
150
151bitflags::bitflags! {
152 #[derive(Default, Copy, Clone, Debug)]
154 #[repr(transparent)]
155 pub struct FileSignals: u32 {
156 const READ_BUFFER_GREW = 1 << 0;
158 }
159}
160
161#[derive(Clone)]
163pub enum File {
164 Pipe(Arc<AtomicRefCell<pipe::Pipe>>),
165 EventFd(Arc<AtomicRefCell<eventfd::EventFd>>),
166 Socket(Socket),
167 TimerFd(Arc<AtomicRefCell<timerfd::TimerFd>>),
168 Epoll(Arc<AtomicRefCell<epoll::Epoll>>),
169}
170
171impl IsSend for File {}
173impl IsSync for File {}
174
175impl File {
176 pub fn borrow(&self) -> FileRef {
177 match self {
178 Self::Pipe(f) => FileRef::Pipe(f.borrow()),
179 Self::EventFd(f) => FileRef::EventFd(f.borrow()),
180 Self::Socket(f) => FileRef::Socket(f.borrow()),
181 Self::TimerFd(f) => FileRef::TimerFd(f.borrow()),
182 Self::Epoll(f) => FileRef::Epoll(f.borrow()),
183 }
184 }
185
186 pub fn try_borrow(&self) -> Result<FileRef, atomic_refcell::BorrowError> {
187 Ok(match self {
188 Self::Pipe(f) => FileRef::Pipe(f.try_borrow()?),
189 Self::EventFd(f) => FileRef::EventFd(f.try_borrow()?),
190 Self::Socket(f) => FileRef::Socket(f.try_borrow()?),
191 Self::TimerFd(f) => FileRef::TimerFd(f.try_borrow()?),
192 Self::Epoll(f) => FileRef::Epoll(f.try_borrow()?),
193 })
194 }
195
196 pub fn borrow_mut(&self) -> FileRefMut {
197 match self {
198 Self::Pipe(f) => FileRefMut::Pipe(f.borrow_mut()),
199 Self::EventFd(f) => FileRefMut::EventFd(f.borrow_mut()),
200 Self::Socket(f) => FileRefMut::Socket(f.borrow_mut()),
201 Self::TimerFd(f) => FileRefMut::TimerFd(f.borrow_mut()),
202 Self::Epoll(f) => FileRefMut::Epoll(f.borrow_mut()),
203 }
204 }
205
206 pub fn try_borrow_mut(&self) -> Result<FileRefMut, atomic_refcell::BorrowMutError> {
207 Ok(match self {
208 Self::Pipe(f) => FileRefMut::Pipe(f.try_borrow_mut()?),
209 Self::EventFd(f) => FileRefMut::EventFd(f.try_borrow_mut()?),
210 Self::Socket(f) => FileRefMut::Socket(f.try_borrow_mut()?),
211 Self::TimerFd(f) => FileRefMut::TimerFd(f.try_borrow_mut()?),
212 Self::Epoll(f) => FileRefMut::Epoll(f.try_borrow_mut()?),
213 })
214 }
215
216 pub fn canonical_handle(&self) -> usize {
217 match self {
218 Self::Pipe(f) => Arc::as_ptr(f) as usize,
219 Self::EventFd(f) => Arc::as_ptr(f) as usize,
220 Self::Socket(f) => f.canonical_handle(),
221 Self::TimerFd(f) => Arc::as_ptr(f) as usize,
222 Self::Epoll(f) => Arc::as_ptr(f) as usize,
223 }
224 }
225}
226
227impl std::fmt::Debug for File {
228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229 match self {
230 Self::Pipe(_) => write!(f, "Pipe")?,
231 Self::EventFd(_) => write!(f, "EventFd")?,
232 Self::Socket(_) => write!(f, "Socket")?,
233 Self::TimerFd(_) => write!(f, "TimerFd")?,
234 Self::Epoll(_) => write!(f, "Epoll")?,
235 }
236
237 if let Ok(file) = self.try_borrow() {
238 let state = file.state();
239 let status = file.status();
240 write!(f, "(state: {state:?}, status: {status:?})")
241 } else {
242 write!(f, "(already borrowed)")
243 }
244 }
245}
246
247pub enum FileRef<'a> {
249 Pipe(atomic_refcell::AtomicRef<'a, pipe::Pipe>),
250 EventFd(atomic_refcell::AtomicRef<'a, eventfd::EventFd>),
251 Socket(SocketRef<'a>),
252 TimerFd(atomic_refcell::AtomicRef<'a, timerfd::TimerFd>),
253 Epoll(atomic_refcell::AtomicRef<'a, epoll::Epoll>),
254}
255
256pub enum FileRefMut<'a> {
259 Pipe(atomic_refcell::AtomicRefMut<'a, pipe::Pipe>),
260 EventFd(atomic_refcell::AtomicRefMut<'a, eventfd::EventFd>),
261 Socket(SocketRefMut<'a>),
262 TimerFd(atomic_refcell::AtomicRefMut<'a, timerfd::TimerFd>),
263 Epoll(atomic_refcell::AtomicRefMut<'a, epoll::Epoll>),
264}
265
266impl FileRef<'_> {
267 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
268 pub fn state(&self) -> FileState
269 );
270 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
271 pub fn mode(&self) -> FileMode
272 );
273 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
274 pub fn status(&self) -> FileStatus
275 );
276 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
277 pub fn stat(&self) -> Result<linux_api::stat::stat, SyscallError>
278 );
279 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
280 pub fn has_open_file(&self) -> bool
281 );
282 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
283 pub fn supports_sa_restart(&self) -> bool
284 );
285}
286
287impl FileRefMut<'_> {
288 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
289 pub fn state(&self) -> FileState
290 );
291 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
292 pub fn mode(&self) -> FileMode
293 );
294 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
295 pub fn status(&self) -> FileStatus
296 );
297 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
298 pub fn stat(&self) -> Result<linux_api::stat::stat, SyscallError>
299 );
300 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
301 pub fn has_open_file(&self) -> bool
302 );
303 enum_passthrough!(self, (), Pipe, EventFd, Socket, TimerFd, Epoll;
304 pub fn supports_sa_restart(&self) -> bool
305 );
306 enum_passthrough!(self, (val), Pipe, EventFd, Socket, TimerFd, Epoll;
307 pub fn set_has_open_file(&mut self, val: bool)
308 );
309 enum_passthrough!(self, (cb_queue), Pipe, EventFd, Socket, TimerFd, Epoll;
310 pub fn close(&mut self, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError>
311 );
312 enum_passthrough!(self, (status), Pipe, EventFd, Socket, TimerFd, Epoll;
313 pub fn set_status(&mut self, status: FileStatus)
314 );
315 enum_passthrough!(self, (request, arg_ptr, memory_manager), Pipe, EventFd, Socket, TimerFd, Epoll;
316 pub fn ioctl(&mut self, request: IoctlRequest, arg_ptr: ForeignPtr<()>, memory_manager: &mut MemoryManager) -> SyscallResult
317 );
318 enum_passthrough!(self, (monitoring_state, monitoring_signals, filter, notify_fn), Pipe, EventFd, Socket, TimerFd, Epoll;
319 pub fn add_listener(
320 &mut self,
321 monitoring_state: FileState,
322 monitoring_signals: FileSignals,
323 filter: StateListenerFilter,
324 notify_fn: impl Fn(FileState, FileState, FileSignals, &mut CallbackQueue) + Send + Sync + 'static,
325 ) -> StateListenHandle
326 );
327 enum_passthrough!(self, (ptr), Pipe, EventFd, Socket, TimerFd, Epoll;
328 pub fn add_legacy_listener(&mut self, ptr: HostTreePointer<c::StatusListener>)
329 );
330 enum_passthrough!(self, (ptr), Pipe, EventFd, Socket, TimerFd, Epoll;
331 pub fn remove_legacy_listener(&mut self, ptr: *mut c::StatusListener)
332 );
333 enum_passthrough!(self, (iovs, offset, flags, mem, cb_queue), Pipe, EventFd, Socket, TimerFd, Epoll;
334 pub fn readv(&mut self, iovs: &[IoVec], offset: Option<libc::off_t>, flags: libc::c_int,
335 mem: &mut MemoryManager, cb_queue: &mut CallbackQueue) -> Result<libc::ssize_t, SyscallError>
336 );
337 enum_passthrough!(self, (iovs, offset, flags, mem, cb_queue), Pipe, EventFd, Socket, TimerFd, Epoll;
338 pub fn writev(&mut self, iovs: &[IoVec], offset: Option<libc::off_t>, flags: libc::c_int,
339 mem: &mut MemoryManager, cb_queue: &mut CallbackQueue) -> Result<libc::ssize_t, SyscallError>
340 );
341}
342
343impl std::fmt::Debug for FileRef<'_> {
344 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
345 match self {
346 Self::Pipe(_) => write!(f, "Pipe")?,
347 Self::EventFd(_) => write!(f, "EventFd")?,
348 Self::Socket(_) => write!(f, "Socket")?,
349 Self::TimerFd(_) => write!(f, "TimerFd")?,
350 Self::Epoll(_) => write!(f, "Epoll")?,
351 }
352
353 let state = self.state();
354 let status = self.status();
355 write!(f, "(state: {state:?}, status: {status:?})")
356 }
357}
358
359impl std::fmt::Debug for FileRefMut<'_> {
360 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
361 match self {
362 Self::Pipe(_) => write!(f, "Pipe")?,
363 Self::EventFd(_) => write!(f, "EventFd")?,
364 Self::Socket(_) => write!(f, "Socket")?,
365 Self::TimerFd(_) => write!(f, "TimerFd")?,
366 Self::Epoll(_) => write!(f, "Epoll")?,
367 }
368
369 let state = self.state();
370 let status = self.status();
371 write!(f, "(state: {state:?}, status: {status:?})")
372 }
373}
374
375#[derive(Clone, Debug)]
390pub struct OpenFile {
391 inner: Arc<OpenFileInner>,
392 _counter: ObjectCounter,
393}
394
395impl IsSend for OpenFile {}
397impl IsSync for OpenFile {}
398
399impl OpenFile {
400 pub fn new(file: File) -> Self {
401 {
402 let mut file = file.borrow_mut();
403
404 if file.state().contains(FileState::CLOSED) {
405 debug_panic!("Creating an `OpenFile` object for a closed file");
407 }
408
409 if file.has_open_file() {
410 debug_panic!(
412 "Creating an `OpenFile` object for a file that already has an `OpenFile` object"
413 );
414 }
415
416 file.set_has_open_file(true);
417 }
418
419 Self {
420 inner: Arc::new(OpenFileInner::new(file)),
421 _counter: ObjectCounter::new("OpenFile"),
422 }
423 }
424
425 pub fn inner_file(&self) -> &File {
426 self.inner.file.as_ref().unwrap()
427 }
428
429 pub fn close(self, cb_queue: &mut CallbackQueue) -> Option<Result<(), SyscallError>> {
433 let OpenFile { inner, _counter } = self;
434
435 Arc::into_inner(inner).map(|inner| inner.close(cb_queue))
437 }
438}
439
440#[derive(Clone, Debug)]
441struct OpenFileInner {
442 file: Option<File>,
443 _counter: ObjectCounter,
444}
445
446impl OpenFileInner {
447 pub fn new(file: File) -> Self {
448 Self {
449 file: Some(file),
450 _counter: ObjectCounter::new("OpenFileInner"),
451 }
452 }
453
454 pub fn close(mut self, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError> {
455 self.close_helper(cb_queue)
456 }
457
458 fn close_helper(&mut self, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError> {
459 if let Some(file) = self.file.take() {
460 file.borrow_mut().close(cb_queue)?;
461 }
462 Ok(())
463 }
464}
465
466impl std::ops::Drop for OpenFileInner {
467 fn drop(&mut self) {
468 let _ = CallbackQueue::queue_and_run_with_legacy(|cb_queue| self.close_helper(cb_queue));
470 }
471}
472
473#[derive(Debug, Clone)]
476pub struct Descriptor {
477 file: CompatFile,
479 flags: DescriptorFlags,
481 _counter: ObjectCounter,
482}
483
484impl IsSend for Descriptor {}
486impl IsSync for Descriptor {}
487
488impl Descriptor {
489 pub fn new(file: CompatFile) -> Self {
490 Self {
491 file,
492 flags: DescriptorFlags::empty(),
493 _counter: ObjectCounter::new("Descriptor"),
494 }
495 }
496
497 pub fn file(&self) -> &CompatFile {
498 &self.file
499 }
500
501 pub fn flags(&self) -> DescriptorFlags {
502 self.flags
503 }
504
505 pub fn set_flags(&mut self, flags: DescriptorFlags) {
506 self.flags = flags;
507 }
508
509 pub fn into_file(self) -> CompatFile {
510 self.file
511 }
512
513 pub fn close(
515 self,
516 host: &Host,
517 cb_queue: &mut CallbackQueue,
518 ) -> Option<Result<(), SyscallError>> {
519 self.file.close(host, cb_queue)
520 }
521
522 pub fn dup(&self, flags: DescriptorFlags) -> Self {
526 Self {
527 file: self.file.clone(),
528 flags,
529 _counter: ObjectCounter::new("Descriptor"),
530 }
531 }
532
533 pub fn into_raw(descriptor: Box<Self>) -> *mut Self {
534 Box::into_raw(descriptor)
535 }
536
537 pub fn from_raw(descriptor: *mut Self) -> Option<Box<Self>> {
538 if descriptor.is_null() {
539 return None;
540 }
541
542 unsafe { Some(Box::from_raw(descriptor)) }
543 }
544
545 pub unsafe fn from_legacy_file(
557 legacy_file: *mut c::LegacyFile,
558 descriptor_flags: OFlag,
559 ) -> Descriptor {
560 assert!(!legacy_file.is_null());
561
562 assert_ne!(
564 unsafe { c::legacyfile_getType(legacy_file) },
565 c::_LegacyFileType_DT_TCPSOCKET,
566 );
567
568 let mut descriptor = Descriptor::new(CompatFile::Legacy(LegacyFileCounter::new(
569 CountedLegacyFileRef::new(HostTreePointer::new(legacy_file)),
570 )));
571
572 let (descriptor_flags, remaining) = DescriptorFlags::from_o_flags(descriptor_flags);
573 assert!(remaining.is_empty());
574 descriptor.set_flags(descriptor_flags);
575 descriptor
576 }
577}
578
579#[derive(Debug)]
582pub struct CountedLegacyFileRef(HostTreePointer<c::LegacyFile>);
583
584impl CountedLegacyFileRef {
585 pub fn new(ptr: HostTreePointer<c::LegacyFile>) -> Self {
588 Self(ptr)
589 }
590
591 pub unsafe fn ptr(&self) -> *mut c::LegacyFile {
595 unsafe { self.0.ptr() }
596 }
597}
598
599impl std::clone::Clone for CountedLegacyFileRef {
600 fn clone(&self) -> Self {
601 unsafe { c::legacyfile_ref(self.0.ptr() as *mut core::ffi::c_void) };
603 Self(self.0)
604 }
605}
606
607impl Drop for CountedLegacyFileRef {
608 fn drop(&mut self) {
609 unsafe { c::legacyfile_unref(self.0.ptr() as *mut core::ffi::c_void) };
611 }
612}
613
614#[derive(Clone, Debug)]
620pub struct LegacyFileCounter {
621 file: Option<CountedLegacyFileRef>,
622 open_count: Arc<()>,
624}
625
626impl LegacyFileCounter {
627 pub fn new(file: CountedLegacyFileRef) -> Self {
628 Self {
629 file: Some(file),
630 open_count: Arc::new(()),
631 }
632 }
633
634 pub fn ptr(&self) -> *mut c::LegacyFile {
635 unsafe { self.file.as_ref().unwrap().ptr() }
636 }
637
638 fn close_helper(&mut self, host: &Host) {
640 if Arc::<()>::strong_count(&self.open_count) == 1 {
643 if let Some(file) = self.file.take() {
644 unsafe { c::legacyfile_close(file.ptr(), host) }
645 }
646 }
647 }
648
649 pub fn close(mut self, host: &Host) {
652 self.close_helper(host);
653 }
654}
655
656impl std::ops::Drop for LegacyFileCounter {
657 fn drop(&mut self) {
658 worker::Worker::with_active_host(|host| self.close_helper(host)).unwrap();
659 }
660}
661
662#[derive(Clone, Debug)]
664pub enum CompatFile {
665 New(OpenFile),
666 Legacy(LegacyFileCounter),
667}
668
669impl CompatFile {
670 pub fn close(
672 self,
673 host: &Host,
674 cb_queue: &mut CallbackQueue,
675 ) -> Option<Result<(), SyscallError>> {
676 match self {
677 Self::New(file) => file.close(cb_queue),
678 Self::Legacy(file) => {
679 file.close(host);
680 Some(Ok(()))
681 }
682 }
683 }
684}
685
686mod export {
687 use super::*;
688
689 use crate::host::descriptor::socket::inet::InetSocket;
690 use crate::host::descriptor::socket::inet::legacy_tcp::LegacyTcpSocket;
691
692 #[unsafe(no_mangle)]
700 pub unsafe extern "C-unwind" fn descriptor_fromLegacyFile(
701 legacy_file: *mut c::LegacyFile,
702 descriptor_flags: libc::c_int,
703 ) -> *mut Descriptor {
704 let descriptor_flags = OFlag::from_bits(descriptor_flags).unwrap();
705 let descriptor = unsafe { Descriptor::from_legacy_file(legacy_file, descriptor_flags) };
706 Descriptor::into_raw(Box::new(descriptor))
707 }
708
709 #[unsafe(no_mangle)]
714 pub unsafe extern "C-unwind" fn descriptor_fromLegacyTcp(
715 legacy_tcp: *mut c::TCP,
716 descriptor_flags: libc::c_int,
717 ) -> *mut Descriptor {
718 assert!(!legacy_tcp.is_null());
719
720 let tcp = unsafe { LegacyTcpSocket::new_from_legacy(legacy_tcp) };
721 let mut descriptor = Descriptor::new(CompatFile::New(OpenFile::new(File::Socket(
722 Socket::Inet(InetSocket::LegacyTcp(tcp)),
723 ))));
724
725 let descriptor_flags = OFlag::from_bits(descriptor_flags).unwrap();
726 let (descriptor_flags, remaining) = DescriptorFlags::from_o_flags(descriptor_flags);
727 assert!(remaining.is_empty());
728 descriptor.set_flags(descriptor_flags);
729
730 Descriptor::into_raw(Box::new(descriptor))
731 }
732
733 #[unsafe(no_mangle)]
737 pub extern "C-unwind" fn descriptor_asLegacyFile(
738 descriptor: *const Descriptor,
739 ) -> *mut c::LegacyFile {
740 assert!(!descriptor.is_null());
741
742 let descriptor = unsafe { &*descriptor };
743
744 if let CompatFile::Legacy(d) = descriptor.file() {
745 d.ptr()
746 } else {
747 std::ptr::null_mut()
748 }
749 }
750
751 #[unsafe(no_mangle)]
755 pub extern "C-unwind" fn descriptor_borrowOpenFile(
756 descriptor: *const Descriptor,
757 ) -> *const OpenFile {
758 assert!(!descriptor.is_null());
759
760 let descriptor = unsafe { &*descriptor };
761
762 match descriptor.file() {
763 CompatFile::Legacy(_) => std::ptr::null_mut(),
764 CompatFile::New(d) => d,
765 }
766 }
767
768 #[unsafe(no_mangle)]
773 pub extern "C-unwind" fn descriptor_newRefOpenFile(
774 descriptor: *const Descriptor,
775 ) -> *const OpenFile {
776 assert!(!descriptor.is_null());
777
778 let descriptor = unsafe { &*descriptor };
779
780 match descriptor.file() {
781 CompatFile::Legacy(_) => std::ptr::null_mut(),
782 CompatFile::New(d) => Box::into_raw(Box::new(d.clone())),
783 }
784 }
785
786 #[unsafe(no_mangle)]
788 pub extern "C-unwind" fn descriptor_setFlags(descriptor: *mut Descriptor, flags: libc::c_int) {
789 assert!(!descriptor.is_null());
790
791 let descriptor = unsafe { &mut *descriptor };
792 let flags = OFlag::from_bits(flags).unwrap();
793 let (flags, remaining_flags) = DescriptorFlags::from_o_flags(flags);
794 assert!(remaining_flags.is_empty());
795
796 descriptor.set_flags(flags);
797 }
798
799 #[unsafe(no_mangle)]
802 pub extern "C-unwind" fn openfile_drop(file: *const OpenFile) {
803 assert!(!file.is_null());
804
805 drop(unsafe { Box::from_raw(file.cast_mut()) });
806 }
807
808 #[unsafe(no_mangle)]
810 pub extern "C-unwind" fn openfile_getStatus(file: *const OpenFile) -> FileState {
811 assert!(!file.is_null());
812
813 let file = unsafe { &*file };
814
815 file.inner_file().borrow().state()
816 }
817
818 #[unsafe(no_mangle)]
822 pub unsafe extern "C-unwind" fn openfile_addListener(
823 file: *const OpenFile,
824 listener: *mut c::StatusListener,
825 ) {
826 assert!(!file.is_null());
827 assert!(!listener.is_null());
828
829 let file = unsafe { &*file };
830
831 file.inner_file()
832 .borrow_mut()
833 .add_legacy_listener(HostTreePointer::new(listener));
834 }
835
836 #[unsafe(no_mangle)]
838 pub extern "C-unwind" fn openfile_removeListener(
839 file: *const OpenFile,
840 listener: *mut c::StatusListener,
841 ) {
842 assert!(!file.is_null());
843 assert!(!listener.is_null());
844
845 let file = unsafe { &*file };
846
847 file.inner_file()
848 .borrow_mut()
849 .remove_legacy_listener(listener);
850 }
851
852 #[unsafe(no_mangle)]
855 pub extern "C-unwind" fn openfile_getCanonicalHandle(file: *const OpenFile) -> libc::uintptr_t {
856 assert!(!file.is_null());
857
858 let file = unsafe { &*file };
859
860 file.inner_file().canonical_handle()
861 }
862
863 #[unsafe(no_mangle)]
867 pub extern "C-unwind" fn descriptor_newRefFile(descriptor: *const Descriptor) -> *const File {
868 assert!(!descriptor.is_null());
869
870 let descriptor = unsafe { &*descriptor };
871
872 match descriptor.file() {
873 CompatFile::Legacy(_) => std::ptr::null_mut(),
874 CompatFile::New(d) => Box::into_raw(Box::new(d.inner_file().clone())),
875 }
876 }
877
878 #[unsafe(no_mangle)]
881 pub extern "C-unwind" fn file_drop(file: *const File) {
882 assert!(!file.is_null());
883
884 drop(unsafe { Box::from_raw(file.cast_mut()) });
885 }
886
887 #[unsafe(no_mangle)]
891 pub extern "C-unwind" fn file_cloneRef(file: *const File) -> *const File {
892 let file = unsafe { file.as_ref() }.unwrap();
893 Box::into_raw(Box::new(file.clone()))
894 }
895
896 #[unsafe(no_mangle)]
898 pub extern "C-unwind" fn file_getStatus(file: *const File) -> FileState {
899 assert!(!file.is_null());
900
901 let file = unsafe { &*file };
902
903 file.borrow().state()
904 }
905
906 #[unsafe(no_mangle)]
910 pub unsafe extern "C-unwind" fn file_addListener(
911 file: *const File,
912 listener: *mut c::StatusListener,
913 ) {
914 assert!(!file.is_null());
915 assert!(!listener.is_null());
916
917 let file = unsafe { &*file };
918
919 file.borrow_mut()
920 .add_legacy_listener(HostTreePointer::new(listener));
921 }
922
923 #[unsafe(no_mangle)]
925 pub extern "C-unwind" fn file_removeListener(
926 file: *const File,
927 listener: *mut c::StatusListener,
928 ) {
929 assert!(!file.is_null());
930 assert!(!listener.is_null());
931
932 let file = unsafe { &*file };
933
934 file.borrow_mut().remove_legacy_listener(listener);
935 }
936
937 #[unsafe(no_mangle)]
940 pub extern "C-unwind" fn file_getCanonicalHandle(file: *const File) -> libc::uintptr_t {
941 assert!(!file.is_null());
942
943 let file = unsafe { &*file };
944
945 file.canonical_handle()
946 }
947}
948
949#[cfg(test)]
950mod tests {
951 use super::*;
952 use crate::host::syscall::Trigger;
953 use crate::host::syscall::condition::SyscallCondition;
954 use crate::host::syscall::types::{
955 Blocked, Failed, SyscallError, SyscallReturn, SyscallReturnBlocked, SyscallReturnDone,
956 };
957
958 #[test]
959 #[cfg_attr(miri, ignore)]
961 fn test_syscallresult_roundtrip() {
962 for val in vec![
963 Ok(1.into()),
964 Err(linux_api::errno::Errno::EPERM.into()),
965 Err(SyscallError::Failed(Failed {
966 errno: linux_api::errno::Errno::EINTR,
967 restartable: true,
968 })),
969 Err(SyscallError::Failed(Failed {
970 errno: linux_api::errno::Errno::EINTR,
971 restartable: false,
972 })),
973 Err(SyscallError::Blocked(Blocked {
974 condition: SyscallCondition::new(Trigger::from(c::Trigger {
975 type_: 1,
976 object: c::TriggerObject {
977 as_pointer: std::ptr::null_mut(),
978 },
979 state: FileState::CLOSED,
980 })),
981 restartable: true,
982 })),
983 ]
984 .drain(..)
985 {
986 let orig_debug = format!("{:?}", &val);
990 let roundtripped = SyscallResult::from(SyscallReturn::from(val));
991 let roundtripped_debug = format!("{:?}", roundtripped);
992 assert_eq!(orig_debug, roundtripped_debug);
993 }
994 }
995
996 #[test]
997 #[cfg_attr(miri, ignore)]
999 fn test_syscallreturn_roundtrip() {
1000 let condition = SyscallCondition::new(Trigger::from(c::Trigger {
1001 type_: 1,
1002 object: c::TriggerObject {
1003 as_pointer: std::ptr::null_mut(),
1004 },
1005 state: FileState::CLOSED,
1006 }));
1007 for val in vec![
1008 SyscallReturn::Done(SyscallReturnDone {
1009 retval: 1.into(),
1010 restartable: false,
1011 }),
1012 SyscallReturn::Block(SyscallReturnBlocked {
1013 cond: condition.into_inner(),
1014 restartable: true,
1015 }),
1016 SyscallReturn::Native,
1017 ]
1018 .drain(..)
1019 {
1020 let orig_debug = format!("{:?}", &val);
1025 let roundtripped = SyscallReturn::from(SyscallResult::from(val));
1026 let roundtripped_debug = format!("{:?}", roundtripped);
1027 assert_eq!(orig_debug, roundtripped_debug);
1028 }
1029 }
1030
1031 #[test]
1032 fn test_file_mode_o_flags() {
1033 assert_eq!(
1035 FileMode::from_o_flags(OFlag::O_PATH),
1036 Ok((FileMode::empty(), OFlag::empty()))
1037 );
1038 assert_eq!(
1039 FileMode::from_o_flags(OFlag::O_WRONLY),
1040 Ok((FileMode::WRITE, OFlag::empty()))
1041 );
1042 assert_eq!(
1043 FileMode::from_o_flags(OFlag::O_RDWR),
1044 Ok((FileMode::READ | FileMode::WRITE, OFlag::empty()))
1045 );
1046 assert_eq!(
1047 FileMode::from_o_flags(OFlag::O_RDONLY),
1048 Ok((FileMode::READ, OFlag::empty()))
1049 );
1050 assert_eq!(
1051 FileMode::from_o_flags(OFlag::empty()),
1052 Ok((FileMode::READ, OFlag::empty()))
1053 );
1054 assert_eq!(
1055 FileMode::from_o_flags(OFlag::O_RDWR | OFlag::O_WRONLY),
1056 Err(())
1057 );
1058 assert_eq!(
1059 FileMode::from_o_flags(OFlag::O_RDWR | OFlag::O_RDONLY),
1060 Ok((FileMode::READ | FileMode::WRITE, OFlag::empty()))
1061 );
1062 assert_eq!(
1063 FileMode::from_o_flags(OFlag::O_WRONLY | OFlag::O_RDONLY),
1064 Ok((FileMode::WRITE, OFlag::empty()))
1065 );
1066 assert_eq!(
1067 FileMode::from_o_flags(OFlag::O_PATH | OFlag::O_WRONLY),
1068 Err(())
1069 );
1070 assert_eq!(
1071 FileMode::from_o_flags(OFlag::O_WRONLY | OFlag::O_CLOEXEC),
1072 Ok((FileMode::WRITE, OFlag::O_CLOEXEC))
1073 );
1074
1075 assert_eq!(FileMode::as_o_flags(&FileMode::empty()), OFlag::O_PATH);
1077 assert_eq!(FileMode::as_o_flags(&FileMode::READ), OFlag::O_RDONLY);
1078 assert_eq!(FileMode::as_o_flags(&FileMode::WRITE), OFlag::O_WRONLY);
1079 assert_eq!(
1080 FileMode::as_o_flags(&(FileMode::READ | FileMode::WRITE)),
1081 OFlag::O_RDWR
1082 );
1083 }
1084}