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