1use std::{
2 ffi::CString,
3 io,
4 marker::PhantomPinned,
5 net::Shutdown,
6 os::fd::{AsFd, AsRawFd, OwnedFd},
7 pin::Pin,
8};
9
10use compio_buf::{IntoInner, IoBuf, IoBufMut, IoVectoredBuf, IoVectoredBufMut};
11#[cfg(not(gnulinux))]
12use libc::open;
13#[cfg(gnulinux)]
14use libc::open64 as open;
15#[cfg(not(any(
16 all(target_os = "linux", not(target_env = "musl")),
17 target_os = "android",
18 target_os = "l4re",
19 target_os = "hurd"
20)))]
21use libc::{ftruncate as ftruncate64, off_t as off64_t};
22#[cfg(any(
23 all(target_os = "linux", not(target_env = "musl")),
24 target_os = "android",
25 target_os = "l4re",
26 target_os = "hurd"
27))]
28use libc::{ftruncate64, off64_t};
29use pin_project_lite::pin_project;
30use socket2::{SockAddr, SockAddrStorage, socklen_t};
31
32use crate::{op::*, sys::aio::*, sys_slice::*, syscall};
33
34pub struct OpenFile {
36 pub(crate) path: CString,
37 pub(crate) flags: i32,
38 pub(crate) mode: libc::mode_t,
39}
40
41impl OpenFile {
42 pub fn new(path: CString, flags: i32, mode: libc::mode_t) -> Self {
44 Self { path, flags, mode }
45 }
46
47 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
48 Ok(syscall!(open(
49 self.path.as_ptr(),
50 self.flags | libc::O_CLOEXEC,
51 self.mode as libc::c_int
52 ))? as _)
53 }
54}
55
56impl CloseFile {
57 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
58 Ok(syscall!(libc::close(self.fd.as_fd().as_raw_fd()))? as _)
59 }
60}
61
62#[derive(Debug)]
63pub struct TruncateFile<S: AsFd> {
66 pub(crate) fd: S,
67 pub(crate) size: u64,
68}
69
70impl<S: AsFd> TruncateFile<S> {
71 pub fn new(fd: S, size: u64) -> Self {
73 Self { fd, size }
74 }
75
76 pub(crate) fn call(&self) -> io::Result<usize> {
77 let size: off64_t = self
78 .size
79 .try_into()
80 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
81 crate::syscall!(ftruncate64(self.fd.as_fd().as_raw_fd(), size)).map(|v| v as _)
82 }
83}
84
85#[cfg(not(gnulinux))]
86pub use libc::stat as Stat;
87#[cfg(gnulinux)]
88pub use libc::stat64 as Stat;
89#[cfg(gnulinux)]
90pub(crate) use libc::statx as Statx;
91
92#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
93#[repr(C)]
94pub(crate) struct StatxTimestamp {
95 pub tv_sec: i64,
96 pub tv_nsec: u32,
97 pub __statx_timestamp_pad1: [i32; 1],
98}
99
100#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
101#[repr(C)]
102pub(crate) struct Statx {
103 pub stx_mask: u32,
104 pub stx_blksize: u32,
105 pub stx_attributes: u64,
106 pub stx_nlink: u32,
107 pub stx_uid: u32,
108 pub stx_gid: u32,
109 pub stx_mode: u16,
110 __statx_pad1: [u16; 1],
111 pub stx_ino: u64,
112 pub stx_size: u64,
113 pub stx_blocks: u64,
114 pub stx_attributes_mask: u64,
115 pub stx_atime: StatxTimestamp,
116 pub stx_btime: StatxTimestamp,
117 pub stx_ctime: StatxTimestamp,
118 pub stx_mtime: StatxTimestamp,
119 pub stx_rdev_major: u32,
120 pub stx_rdev_minor: u32,
121 pub stx_dev_major: u32,
122 pub stx_dev_minor: u32,
123 pub stx_mnt_id: u64,
124 pub stx_dio_mem_align: u32,
125 pub stx_dio_offset_align: u32,
126 __statx_pad3: [u64; 12],
127}
128
129#[cfg(target_os = "linux")]
130pub(crate) const fn statx_mask() -> u32 {
131 libc::STATX_TYPE
133 | libc::STATX_MODE
134 | libc::STATX_NLINK
135 | libc::STATX_UID
136 | libc::STATX_GID
137 | libc::STATX_ATIME
138 | libc::STATX_MTIME
139 | libc::STATX_CTIME
140 | libc::STATX_INO
141 | libc::STATX_SIZE
142 | libc::STATX_BLOCKS
143 | libc::STATX_BTIME
144 | libc::STATX_MNT_ID
145 | libc::STATX_DIOALIGN
146}
147
148#[cfg(target_os = "linux")]
149pub(crate) const fn statx_to_stat(statx: Statx) -> Stat {
150 let mut stat: Stat = unsafe { std::mem::zeroed() };
151 stat.st_dev = libc::makedev(statx.stx_dev_major, statx.stx_dev_minor) as _;
152 stat.st_ino = statx.stx_ino as _;
153 stat.st_nlink = statx.stx_nlink as _;
154 stat.st_mode = statx.stx_mode as _;
155 stat.st_uid = statx.stx_uid as _;
156 stat.st_gid = statx.stx_gid as _;
157 stat.st_rdev = libc::makedev(statx.stx_rdev_major, statx.stx_rdev_minor) as _;
158 stat.st_size = statx.stx_size as _;
159 stat.st_blksize = statx.stx_blksize as _;
160 stat.st_blocks = statx.stx_blocks as _;
161 stat.st_atime = statx.stx_atime.tv_sec as _;
162 stat.st_atime_nsec = statx.stx_atime.tv_nsec as _;
163 stat.st_mtime = statx.stx_mtime.tv_sec as _;
164 stat.st_mtime_nsec = statx.stx_mtime.tv_nsec as _;
165 stat.st_ctime = statx.stx_btime.tv_sec as _;
166 stat.st_ctime_nsec = statx.stx_btime.tv_nsec as _;
167 stat
168}
169
170pin_project! {
171 pub struct ReadVectoredAt<T: IoVectoredBufMut, S> {
173 pub(crate) fd: S,
174 pub(crate) offset: u64,
175 #[pin]
176 pub(crate) buffer: T,
177 pub(crate) slices: Vec<SysSlice>,
178 pub(crate) aiocb: aiocb,
179 _p: PhantomPinned,
180 }
181}
182
183impl<T: IoVectoredBufMut, S> ReadVectoredAt<T, S> {
184 pub fn new(fd: S, offset: u64, buffer: T) -> Self {
186 Self {
187 fd,
188 offset,
189 buffer,
190 slices: vec![],
191 aiocb: new_aiocb(),
192 _p: PhantomPinned,
193 }
194 }
195}
196
197impl<T: IoVectoredBufMut, S> IntoInner for ReadVectoredAt<T, S> {
198 type Inner = T;
199
200 fn into_inner(self) -> Self::Inner {
201 self.buffer
202 }
203}
204
205pin_project! {
206 pub struct WriteVectoredAt<T: IoVectoredBuf, S> {
208 pub(crate) fd: S,
209 pub(crate) offset: u64,
210 #[pin]
211 pub(crate) buffer: T,
212 pub(crate) slices: Vec<SysSlice>,
213 pub(crate) aiocb: aiocb,
214 _p: PhantomPinned,
215 }
216}
217impl<T: IoVectoredBuf, S> WriteVectoredAt<T, S> {
218 pub fn new(fd: S, offset: u64, buffer: T) -> Self {
220 Self {
221 fd,
222 offset,
223 buffer,
224 slices: vec![],
225 aiocb: new_aiocb(),
226 _p: PhantomPinned,
227 }
228 }
229}
230
231impl<T: IoVectoredBuf, S> IntoInner for WriteVectoredAt<T, S> {
232 type Inner = T;
233
234 fn into_inner(self) -> Self::Inner {
235 self.buffer
236 }
237}
238
239pin_project! {
240 pub struct ReadVectored<T: IoVectoredBufMut, S> {
242 pub(crate) fd: S,
243 #[pin]
244 pub(crate) buffer: T,
245 pub(crate) slices: Vec<SysSlice>,
246 _p: PhantomPinned,
247 }
248}
249
250impl<T: IoVectoredBufMut, S> ReadVectored<T, S> {
251 pub fn new(fd: S, buffer: T) -> Self {
253 Self {
254 fd,
255 buffer,
256 slices: vec![],
257 _p: PhantomPinned,
258 }
259 }
260}
261
262impl<T: IoVectoredBufMut, S> IntoInner for ReadVectored<T, S> {
263 type Inner = T;
264
265 fn into_inner(self) -> Self::Inner {
266 self.buffer
267 }
268}
269
270pin_project! {
271 pub struct WriteVectored<T: IoVectoredBuf, S> {
273 pub(crate) fd: S,
274 #[pin]
275 pub(crate) buffer: T,
276 pub(crate) slices: Vec<SysSlice>,
277 _p: PhantomPinned,
278 }
279}
280
281impl<T: IoVectoredBuf, S> WriteVectored<T, S> {
282 pub fn new(fd: S, buffer: T) -> Self {
284 Self {
285 fd,
286 buffer,
287 slices: vec![],
288 _p: PhantomPinned,
289 }
290 }
291}
292
293impl<T: IoVectoredBuf, S> IntoInner for WriteVectored<T, S> {
294 type Inner = T;
295
296 fn into_inner(self) -> Self::Inner {
297 self.buffer
298 }
299}
300
301pub struct Unlink {
303 pub(crate) path: CString,
304 pub(crate) dir: bool,
305}
306
307impl Unlink {
308 pub fn new(path: CString, dir: bool) -> Self {
310 Self { path, dir }
311 }
312
313 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
314 if self.dir {
315 Ok(syscall!(libc::rmdir(self.path.as_ptr()))? as _)
316 } else {
317 Ok(syscall!(libc::unlink(self.path.as_ptr()))? as _)
318 }
319 }
320}
321
322pub struct CreateDir {
324 pub(crate) path: CString,
325 pub(crate) mode: libc::mode_t,
326}
327
328impl CreateDir {
329 pub fn new(path: CString, mode: libc::mode_t) -> Self {
331 Self { path, mode }
332 }
333
334 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
335 Ok(syscall!(libc::mkdir(self.path.as_ptr(), self.mode))? as _)
336 }
337}
338
339pub struct Rename {
341 pub(crate) old_path: CString,
342 pub(crate) new_path: CString,
343}
344
345impl Rename {
346 pub fn new(old_path: CString, new_path: CString) -> Self {
348 Self { old_path, new_path }
349 }
350
351 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
352 Ok(syscall!(libc::rename(self.old_path.as_ptr(), self.new_path.as_ptr()))? as _)
353 }
354}
355
356pub struct Symlink {
358 pub(crate) source: CString,
359 pub(crate) target: CString,
360}
361
362impl Symlink {
363 pub fn new(source: CString, target: CString) -> Self {
365 Self { source, target }
366 }
367
368 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
369 Ok(syscall!(libc::symlink(self.source.as_ptr(), self.target.as_ptr()))? as _)
370 }
371}
372
373pub struct HardLink {
375 pub(crate) source: CString,
376 pub(crate) target: CString,
377}
378
379impl HardLink {
380 pub fn new(source: CString, target: CString) -> Self {
382 Self { source, target }
383 }
384
385 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
386 Ok(syscall!(libc::link(self.source.as_ptr(), self.target.as_ptr()))? as _)
387 }
388}
389
390pub struct CreateSocket {
392 pub(crate) domain: i32,
393 pub(crate) socket_type: i32,
394 pub(crate) protocol: i32,
395}
396
397impl CreateSocket {
398 pub fn new(domain: i32, socket_type: i32, protocol: i32) -> Self {
400 Self {
401 domain,
402 socket_type,
403 protocol,
404 }
405 }
406}
407
408impl<S: AsFd> ShutdownSocket<S> {
409 pub(crate) fn how(&self) -> i32 {
410 match self.how {
411 Shutdown::Write => libc::SHUT_WR,
412 Shutdown::Read => libc::SHUT_RD,
413 Shutdown::Both => libc::SHUT_RDWR,
414 }
415 }
416
417 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
418 Ok(syscall!(libc::shutdown(self.fd.as_fd().as_raw_fd(), self.how()))? as _)
419 }
420}
421
422impl CloseSocket {
423 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
424 Ok(syscall!(libc::close(self.fd.as_fd().as_raw_fd()))? as _)
425 }
426}
427
428pin_project! {
429 pub struct Accept<S> {
431 pub(crate) fd: S,
432 pub(crate) buffer: SockAddrStorage,
433 pub(crate) addr_len: socklen_t,
434 pub(crate) accepted_fd: Option<OwnedFd>,
435 _p: PhantomPinned,
436 }
437}
438
439impl<S> Accept<S> {
440 pub fn new(fd: S) -> Self {
442 let buffer = SockAddrStorage::zeroed();
443 let addr_len = buffer.size_of();
444 Self {
445 fd,
446 buffer,
447 addr_len,
448 accepted_fd: None,
449 _p: PhantomPinned,
450 }
451 }
452
453 pub fn into_addr(mut self) -> SockAddr {
455 std::mem::forget(self.accepted_fd.take());
456 unsafe { SockAddr::new(self.buffer, self.addr_len) }
457 }
458}
459
460pin_project! {
461 pub struct Recv<T: IoBufMut, S> {
466 pub(crate) fd: S,
467 #[pin]
468 pub(crate) buffer: T,
469 pub(crate) flags: i32,
470 _p: PhantomPinned,
471 }
472}
473
474impl<T: IoBufMut, S> Recv<T, S> {
475 pub fn new(fd: S, buffer: T, flags: i32) -> Self {
477 Self {
478 fd,
479 buffer,
480 flags,
481 _p: PhantomPinned,
482 }
483 }
484}
485
486impl<T: IoBufMut, S> IntoInner for Recv<T, S> {
487 type Inner = T;
488
489 fn into_inner(self) -> Self::Inner {
490 self.buffer
491 }
492}
493
494pin_project! {
495 pub struct Send<T: IoBuf, S> {
500 pub(crate) fd: S,
501 #[pin]
502 pub(crate) buffer: T,
503 pub(crate) flags: i32,
504 _p: PhantomPinned,
505 }
506}
507
508impl<T: IoBuf, S> Send<T, S> {
509 pub fn new(fd: S, buffer: T, flags: i32) -> Self {
511 Self {
512 fd,
513 buffer,
514 flags,
515 _p: PhantomPinned,
516 }
517 }
518}
519
520impl<T: IoBuf, S> IntoInner for Send<T, S> {
521 type Inner = T;
522
523 fn into_inner(self) -> Self::Inner {
524 self.buffer
525 }
526}
527
528pin_project! {
529 pub struct RecvVectored<T: IoVectoredBufMut, S> {
531 pub(crate) msg: libc::msghdr,
532 pub(crate) fd: S,
533 #[pin]
534 pub(crate) buffer: T,
535 pub(crate) slices: Vec<SysSlice>,
536 pub(crate) flags: i32,
537 _p: PhantomPinned,
538 }
539}
540
541impl<T: IoVectoredBufMut, S> RecvVectored<T, S> {
542 pub fn new(fd: S, buffer: T, flags: i32) -> Self {
544 Self {
545 msg: unsafe { std::mem::zeroed() },
546 fd,
547 buffer,
548 slices: vec![],
549 flags,
550 _p: PhantomPinned,
551 }
552 }
553
554 pub(crate) fn set_msg(self: Pin<&mut Self>) {
555 let this = self.project();
556
557 *this.slices = this.buffer.sys_slices_mut();
558 this.msg.msg_iov = this.slices.as_mut_ptr() as _;
559 this.msg.msg_iovlen = this.slices.len() as _;
560 }
561}
562
563impl<T: IoVectoredBufMut, S> IntoInner for RecvVectored<T, S> {
564 type Inner = T;
565
566 fn into_inner(self) -> Self::Inner {
567 self.buffer
568 }
569}
570
571pin_project! {
572 pub struct SendVectored<T: IoVectoredBuf, S> {
574 pub(crate) msg: libc::msghdr,
575 pub(crate) fd: S,
576 #[pin]
577 pub(crate) buffer: T,
578 pub(crate) slices: Vec<SysSlice>,
579 pub(crate) flags: i32,
580 _p: PhantomPinned,
581 }
582}
583
584impl<T: IoVectoredBuf, S> SendVectored<T, S> {
585 pub fn new(fd: S, buffer: T, flags: i32) -> Self {
587 Self {
588 msg: unsafe { std::mem::zeroed() },
589 fd,
590 buffer,
591 slices: vec![],
592 flags,
593 _p: PhantomPinned,
594 }
595 }
596
597 pub(crate) fn set_msg(self: Pin<&mut Self>) {
598 let this = self.project();
599
600 *this.slices = this.buffer.as_ref().sys_slices();
601 this.msg.msg_iov = this.slices.as_mut_ptr() as _;
602 this.msg.msg_iovlen = this.slices.len() as _;
603 }
604}
605
606impl<T: IoVectoredBuf, S> IntoInner for SendVectored<T, S> {
607 type Inner = T;
608
609 fn into_inner(self) -> Self::Inner {
610 self.buffer
611 }
612}
613
614pin_project! {
615 pub struct RecvMsg<T: IoVectoredBufMut, C: IoBufMut, S> {
617 pub(crate) msg: libc::msghdr,
618 pub(crate) addr: SockAddrStorage,
619 pub(crate) fd: S,
620 #[pin]
621 pub(crate) buffer: T,
622 pub(crate) control: C,
623 pub(crate) slices: Vec<SysSlice>,
624 pub(crate) flags: i32,
625 _p: PhantomPinned,
626 }
627}
628
629impl<T: IoVectoredBufMut, C: IoBufMut, S> RecvMsg<T, C, S> {
630 pub fn new(fd: S, buffer: T, control: C, flags: i32) -> Self {
636 assert!(
637 control.buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
638 "misaligned control message buffer"
639 );
640 Self {
641 msg: unsafe { std::mem::zeroed() },
642 addr: SockAddrStorage::zeroed(),
643 fd,
644 buffer,
645 control,
646 slices: vec![],
647 flags,
648 _p: PhantomPinned,
649 }
650 }
651
652 pub(crate) fn set_msg(self: Pin<&mut Self>) {
653 let this = self.project();
654 *this.slices = this.buffer.sys_slices_mut();
655
656 this.msg.msg_name = this.addr as *mut _ as _;
657 this.msg.msg_namelen = this.addr.size_of() as _;
658 this.msg.msg_iov = this.slices.as_mut_ptr() as _;
659 this.msg.msg_iovlen = this.slices.len() as _;
660 this.msg.msg_control = this.control.buf_mut_ptr() as _;
661 this.msg.msg_controllen = this.control.buf_capacity() as _;
662 }
663}
664
665impl<T: IoVectoredBufMut, C: IoBufMut, S> IntoInner for RecvMsg<T, C, S> {
666 type Inner = ((T, C), SockAddrStorage, socklen_t, usize);
667
668 fn into_inner(self) -> Self::Inner {
669 (
670 (self.buffer, self.control),
671 self.addr,
672 self.msg.msg_namelen,
673 self.msg.msg_controllen as _,
674 )
675 }
676}
677
678pin_project! {
679 pub struct SendMsg<T: IoVectoredBuf, C: IoBuf, S> {
682 pub(crate) msg: libc::msghdr,
683 pub(crate) fd: S,
684 #[pin]
685 pub(crate) buffer: T,
686 #[pin]
687 pub(crate) control: C,
688 pub(crate) addr: SockAddr,
689 pub(crate) slices: Vec<SysSlice>,
690 pub(crate) flags: i32,
691 _p: PhantomPinned,
692 }
693}
694
695impl<T: IoVectoredBuf, C: IoBuf, S> SendMsg<T, C, S> {
696 pub fn new(fd: S, buffer: T, control: C, addr: SockAddr, flags: i32) -> Self {
702 assert!(
703 control.buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
704 "misaligned control message buffer"
705 );
706 Self {
707 msg: unsafe { std::mem::zeroed() },
708 fd,
709 buffer,
710 control,
711 addr,
712 slices: vec![],
713 flags,
714 _p: PhantomPinned,
715 }
716 }
717
718 pub(crate) fn set_msg(self: Pin<&mut Self>) {
719 let this = self.project();
720 *this.slices = this.buffer.as_ref().sys_slices();
721 this.msg.msg_name = this.addr.as_ptr() as _;
722 this.msg.msg_namelen = this.addr.len();
723 this.msg.msg_iov = this.slices.as_ptr() as _;
724 this.msg.msg_iovlen = this.slices.len() as _;
725 this.msg.msg_control = this.control.buf_ptr() as _;
726 this.msg.msg_controllen = this.control.buf_len() as _;
727 }
728}
729
730impl<T: IoVectoredBuf, C: IoBuf, S> IntoInner for SendMsg<T, C, S> {
731 type Inner = (T, C);
732
733 fn into_inner(self) -> Self::Inner {
734 (self.buffer, self.control)
735 }
736}
737
738#[derive(Debug, Clone, Copy, PartialEq, Eq)]
740pub enum Interest {
741 Readable,
743 Writable,
745}
746
747pub struct PollOnce<S> {
749 pub(crate) fd: S,
750 pub(crate) interest: Interest,
751}
752
753impl<S> PollOnce<S> {
754 pub fn new(fd: S, interest: Interest) -> Self {
756 Self { fd, interest }
757 }
758}
759
760#[cfg(linux_all)]
762pub struct Splice<S1, S2> {
763 pub(crate) fd_in: S1,
764 pub(crate) offset_in: i64,
765 pub(crate) fd_out: S2,
766 pub(crate) offset_out: i64,
767 pub(crate) len: usize,
768 pub(crate) flags: u32,
769}
770
771#[cfg(linux_all)]
772impl<S1, S2> Splice<S1, S2> {
773 pub fn new(
779 fd_in: S1,
780 offset_in: i64,
781 fd_out: S2,
782 offset_out: i64,
783 len: usize,
784 flags: u32,
785 ) -> Self {
786 Self {
787 fd_in,
788 offset_in,
789 fd_out,
790 offset_out,
791 len,
792 flags,
793 }
794 }
795}