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 0x3FFF
134}
135
136#[cfg(target_os = "linux")]
137pub(crate) const fn statx_to_stat(statx: Statx) -> Stat {
138 let mut stat: Stat = unsafe { std::mem::zeroed() };
139 stat.st_dev = libc::makedev(statx.stx_dev_major, statx.stx_dev_minor) as _;
140 stat.st_ino = statx.stx_ino as _;
141 stat.st_nlink = statx.stx_nlink as _;
142 stat.st_mode = statx.stx_mode as _;
143 stat.st_uid = statx.stx_uid as _;
144 stat.st_gid = statx.stx_gid as _;
145 stat.st_rdev = libc::makedev(statx.stx_rdev_major, statx.stx_rdev_minor) as _;
146 stat.st_size = statx.stx_size as _;
147 stat.st_blksize = statx.stx_blksize as _;
148 stat.st_blocks = statx.stx_blocks as _;
149 stat.st_atime = statx.stx_atime.tv_sec as _;
150 stat.st_atime_nsec = statx.stx_atime.tv_nsec as _;
151 stat.st_mtime = statx.stx_mtime.tv_sec as _;
152 stat.st_mtime_nsec = statx.stx_mtime.tv_nsec as _;
153 stat.st_ctime = statx.stx_btime.tv_sec as _;
154 stat.st_ctime_nsec = statx.stx_btime.tv_nsec as _;
155 stat
156}
157
158#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
159pub(crate) const fn stat_to_statx(stat: Stat) -> Statx {
160 let mut statx: Statx = unsafe { std::mem::zeroed() };
161 statx.stx_dev_major = libc::major(stat.st_dev as _) as _;
162 statx.stx_dev_minor = libc::minor(stat.st_dev as _) as _;
163 statx.stx_ino = stat.st_ino as _;
164 statx.stx_nlink = stat.st_nlink as _;
165 statx.stx_mode = stat.st_mode as _;
166 statx.stx_uid = stat.st_uid as _;
167 statx.stx_gid = stat.st_gid as _;
168 statx.stx_rdev_major = libc::major(stat.st_rdev as _) as _;
169 statx.stx_rdev_minor = libc::minor(stat.st_rdev as _) as _;
170 statx.stx_size = stat.st_size as _;
171 statx.stx_blksize = stat.st_blksize as _;
172 statx.stx_blocks = stat.st_blocks as _;
173 statx.stx_atime.tv_sec = stat.st_atime as _;
174 statx.stx_atime.tv_nsec = stat.st_atime_nsec as _;
175 statx.stx_mtime.tv_sec = stat.st_mtime as _;
176 statx.stx_mtime.tv_nsec = stat.st_mtime_nsec as _;
177 statx.stx_btime.tv_sec = stat.st_ctime as _;
178 statx.stx_btime.tv_nsec = stat.st_ctime_nsec as _;
179 statx
180}
181
182pin_project! {
183 pub struct ReadVectoredAt<T: IoVectoredBufMut, S> {
185 pub(crate) fd: S,
186 pub(crate) offset: u64,
187 #[pin]
188 pub(crate) buffer: T,
189 pub(crate) slices: Vec<SysSlice>,
190 pub(crate) aiocb: aiocb,
191 _p: PhantomPinned,
192 }
193}
194
195impl<T: IoVectoredBufMut, S> ReadVectoredAt<T, S> {
196 pub fn new(fd: S, offset: u64, buffer: T) -> Self {
198 Self {
199 fd,
200 offset,
201 buffer,
202 slices: vec![],
203 aiocb: new_aiocb(),
204 _p: PhantomPinned,
205 }
206 }
207}
208
209impl<T: IoVectoredBufMut, S> IntoInner for ReadVectoredAt<T, S> {
210 type Inner = T;
211
212 fn into_inner(self) -> Self::Inner {
213 self.buffer
214 }
215}
216
217pin_project! {
218 pub struct WriteVectoredAt<T: IoVectoredBuf, S> {
220 pub(crate) fd: S,
221 pub(crate) offset: u64,
222 #[pin]
223 pub(crate) buffer: T,
224 pub(crate) slices: Vec<SysSlice>,
225 pub(crate) aiocb: aiocb,
226 _p: PhantomPinned,
227 }
228}
229impl<T: IoVectoredBuf, S> WriteVectoredAt<T, S> {
230 pub fn new(fd: S, offset: u64, buffer: T) -> Self {
232 Self {
233 fd,
234 offset,
235 buffer,
236 slices: vec![],
237 aiocb: new_aiocb(),
238 _p: PhantomPinned,
239 }
240 }
241}
242
243impl<T: IoVectoredBuf, S> IntoInner for WriteVectoredAt<T, S> {
244 type Inner = T;
245
246 fn into_inner(self) -> Self::Inner {
247 self.buffer
248 }
249}
250
251pin_project! {
252 pub struct ReadVectored<T: IoVectoredBufMut, S> {
254 pub(crate) fd: S,
255 #[pin]
256 pub(crate) buffer: T,
257 pub(crate) slices: Vec<SysSlice>,
258 _p: PhantomPinned,
259 }
260}
261
262impl<T: IoVectoredBufMut, S> ReadVectored<T, S> {
263 pub fn new(fd: S, buffer: T) -> Self {
265 Self {
266 fd,
267 buffer,
268 slices: vec![],
269 _p: PhantomPinned,
270 }
271 }
272}
273
274impl<T: IoVectoredBufMut, S> IntoInner for ReadVectored<T, S> {
275 type Inner = T;
276
277 fn into_inner(self) -> Self::Inner {
278 self.buffer
279 }
280}
281
282pin_project! {
283 pub struct WriteVectored<T: IoVectoredBuf, S> {
285 pub(crate) fd: S,
286 #[pin]
287 pub(crate) buffer: T,
288 pub(crate) slices: Vec<SysSlice>,
289 _p: PhantomPinned,
290 }
291}
292
293impl<T: IoVectoredBuf, S> WriteVectored<T, S> {
294 pub fn new(fd: S, buffer: T) -> Self {
296 Self {
297 fd,
298 buffer,
299 slices: vec![],
300 _p: PhantomPinned,
301 }
302 }
303}
304
305impl<T: IoVectoredBuf, S> IntoInner for WriteVectored<T, S> {
306 type Inner = T;
307
308 fn into_inner(self) -> Self::Inner {
309 self.buffer
310 }
311}
312
313pub struct Unlink {
315 pub(crate) path: CString,
316 pub(crate) dir: bool,
317}
318
319impl Unlink {
320 pub fn new(path: CString, dir: bool) -> Self {
322 Self { path, dir }
323 }
324
325 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
326 if self.dir {
327 Ok(syscall!(libc::rmdir(self.path.as_ptr()))? as _)
328 } else {
329 Ok(syscall!(libc::unlink(self.path.as_ptr()))? as _)
330 }
331 }
332}
333
334pub struct CreateDir {
336 pub(crate) path: CString,
337 pub(crate) mode: libc::mode_t,
338}
339
340impl CreateDir {
341 pub fn new(path: CString, mode: libc::mode_t) -> Self {
343 Self { path, mode }
344 }
345
346 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
347 Ok(syscall!(libc::mkdir(self.path.as_ptr(), self.mode))? as _)
348 }
349}
350
351pub struct Rename {
353 pub(crate) old_path: CString,
354 pub(crate) new_path: CString,
355}
356
357impl Rename {
358 pub fn new(old_path: CString, new_path: CString) -> Self {
360 Self { old_path, new_path }
361 }
362
363 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
364 Ok(syscall!(libc::rename(self.old_path.as_ptr(), self.new_path.as_ptr()))? as _)
365 }
366}
367
368pub struct Symlink {
370 pub(crate) source: CString,
371 pub(crate) target: CString,
372}
373
374impl Symlink {
375 pub fn new(source: CString, target: CString) -> Self {
377 Self { source, target }
378 }
379
380 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
381 Ok(syscall!(libc::symlink(self.source.as_ptr(), self.target.as_ptr()))? as _)
382 }
383}
384
385pub struct HardLink {
387 pub(crate) source: CString,
388 pub(crate) target: CString,
389}
390
391impl HardLink {
392 pub fn new(source: CString, target: CString) -> Self {
394 Self { source, target }
395 }
396
397 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
398 Ok(syscall!(libc::link(self.source.as_ptr(), self.target.as_ptr()))? as _)
399 }
400}
401
402pub struct CreateSocket {
404 pub(crate) domain: i32,
405 pub(crate) socket_type: i32,
406 pub(crate) protocol: i32,
407}
408
409impl CreateSocket {
410 pub fn new(domain: i32, socket_type: i32, protocol: i32) -> Self {
412 Self {
413 domain,
414 socket_type,
415 protocol,
416 }
417 }
418}
419
420impl<S: AsFd> ShutdownSocket<S> {
421 pub(crate) fn how(&self) -> i32 {
422 match self.how {
423 Shutdown::Write => libc::SHUT_WR,
424 Shutdown::Read => libc::SHUT_RD,
425 Shutdown::Both => libc::SHUT_RDWR,
426 }
427 }
428
429 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
430 Ok(syscall!(libc::shutdown(self.fd.as_fd().as_raw_fd(), self.how()))? as _)
431 }
432}
433
434impl CloseSocket {
435 pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
436 Ok(syscall!(libc::close(self.fd.as_fd().as_raw_fd()))? as _)
437 }
438}
439
440pin_project! {
441 pub struct Accept<S> {
443 pub(crate) fd: S,
444 pub(crate) buffer: SockAddrStorage,
445 pub(crate) addr_len: socklen_t,
446 pub(crate) accepted_fd: Option<OwnedFd>,
447 _p: PhantomPinned,
448 }
449}
450
451impl<S> Accept<S> {
452 pub fn new(fd: S) -> Self {
454 let buffer = SockAddrStorage::zeroed();
455 let addr_len = buffer.size_of();
456 Self {
457 fd,
458 buffer,
459 addr_len,
460 accepted_fd: None,
461 _p: PhantomPinned,
462 }
463 }
464
465 pub fn into_addr(mut self) -> SockAddr {
467 std::mem::forget(self.accepted_fd.take());
468 unsafe { SockAddr::new(self.buffer, self.addr_len) }
469 }
470}
471
472pin_project! {
473 pub struct Recv<T: IoBufMut, S> {
478 pub(crate) fd: S,
479 #[pin]
480 pub(crate) buffer: T,
481 pub(crate) flags: i32,
482 _p: PhantomPinned,
483 }
484}
485
486impl<T: IoBufMut, S> Recv<T, S> {
487 pub fn new(fd: S, buffer: T, flags: i32) -> Self {
489 Self {
490 fd,
491 buffer,
492 flags,
493 _p: PhantomPinned,
494 }
495 }
496}
497
498impl<T: IoBufMut, S> IntoInner for Recv<T, S> {
499 type Inner = T;
500
501 fn into_inner(self) -> Self::Inner {
502 self.buffer
503 }
504}
505
506pin_project! {
507 pub struct Send<T: IoBuf, S> {
512 pub(crate) fd: S,
513 #[pin]
514 pub(crate) buffer: T,
515 pub(crate) flags: i32,
516 _p: PhantomPinned,
517 }
518}
519
520impl<T: IoBuf, S> Send<T, S> {
521 pub fn new(fd: S, buffer: T, flags: i32) -> Self {
523 Self {
524 fd,
525 buffer,
526 flags,
527 _p: PhantomPinned,
528 }
529 }
530}
531
532impl<T: IoBuf, S> IntoInner for Send<T, S> {
533 type Inner = T;
534
535 fn into_inner(self) -> Self::Inner {
536 self.buffer
537 }
538}
539
540pin_project! {
541 pub struct RecvVectored<T: IoVectoredBufMut, S> {
543 pub(crate) msg: libc::msghdr,
544 pub(crate) fd: S,
545 #[pin]
546 pub(crate) buffer: T,
547 pub(crate) slices: Vec<SysSlice>,
548 pub(crate) flags: i32,
549 _p: PhantomPinned,
550 }
551}
552
553impl<T: IoVectoredBufMut, S> RecvVectored<T, S> {
554 pub fn new(fd: S, buffer: T, flags: i32) -> Self {
556 Self {
557 msg: unsafe { std::mem::zeroed() },
558 fd,
559 buffer,
560 slices: vec![],
561 flags,
562 _p: PhantomPinned,
563 }
564 }
565
566 pub(crate) fn set_msg(self: Pin<&mut Self>) {
567 let this = self.project();
568
569 *this.slices = this.buffer.sys_slices_mut();
570 this.msg.msg_iov = this.slices.as_mut_ptr() as _;
571 this.msg.msg_iovlen = this.slices.len() as _;
572 }
573}
574
575impl<T: IoVectoredBufMut, S> IntoInner for RecvVectored<T, S> {
576 type Inner = T;
577
578 fn into_inner(self) -> Self::Inner {
579 self.buffer
580 }
581}
582
583pin_project! {
584 pub struct SendVectored<T: IoVectoredBuf, S> {
586 pub(crate) msg: libc::msghdr,
587 pub(crate) fd: S,
588 #[pin]
589 pub(crate) buffer: T,
590 pub(crate) slices: Vec<SysSlice>,
591 pub(crate) flags: i32,
592 _p: PhantomPinned,
593 }
594}
595
596impl<T: IoVectoredBuf, S> SendVectored<T, S> {
597 pub fn new(fd: S, buffer: T, flags: i32) -> Self {
599 Self {
600 msg: unsafe { std::mem::zeroed() },
601 fd,
602 buffer,
603 slices: vec![],
604 flags,
605 _p: PhantomPinned,
606 }
607 }
608
609 pub(crate) fn set_msg(self: Pin<&mut Self>) {
610 let this = self.project();
611
612 *this.slices = this.buffer.as_ref().sys_slices();
613 this.msg.msg_iov = this.slices.as_mut_ptr() as _;
614 this.msg.msg_iovlen = this.slices.len() as _;
615 }
616}
617
618impl<T: IoVectoredBuf, S> IntoInner for SendVectored<T, S> {
619 type Inner = T;
620
621 fn into_inner(self) -> Self::Inner {
622 self.buffer
623 }
624}
625
626pin_project! {
627 pub struct RecvMsg<T: IoVectoredBufMut, C: IoBufMut, S> {
629 pub(crate) msg: libc::msghdr,
630 pub(crate) addr: SockAddrStorage,
631 pub(crate) fd: S,
632 #[pin]
633 pub(crate) buffer: T,
634 pub(crate) control: C,
635 pub(crate) slices: Vec<SysSlice>,
636 pub(crate) flags: i32,
637 _p: PhantomPinned,
638 }
639}
640
641impl<T: IoVectoredBufMut, C: IoBufMut, S> RecvMsg<T, C, S> {
642 pub fn new(fd: S, buffer: T, control: C, flags: i32) -> Self {
648 assert!(
649 control.buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
650 "misaligned control message buffer"
651 );
652 Self {
653 msg: unsafe { std::mem::zeroed() },
654 addr: SockAddrStorage::zeroed(),
655 fd,
656 buffer,
657 control,
658 slices: vec![],
659 flags,
660 _p: PhantomPinned,
661 }
662 }
663
664 pub(crate) fn set_msg(self: Pin<&mut Self>) {
665 let this = self.project();
666 *this.slices = this.buffer.sys_slices_mut();
667
668 this.msg.msg_name = this.addr as *mut _ as _;
669 this.msg.msg_namelen = this.addr.size_of() as _;
670 this.msg.msg_iov = this.slices.as_mut_ptr() as _;
671 this.msg.msg_iovlen = this.slices.len() as _;
672 this.msg.msg_control = this.control.buf_mut_ptr() as _;
673 this.msg.msg_controllen = this.control.buf_capacity() as _;
674 }
675}
676
677impl<T: IoVectoredBufMut, C: IoBufMut, S> IntoInner for RecvMsg<T, C, S> {
678 type Inner = ((T, C), SockAddrStorage, socklen_t, usize);
679
680 fn into_inner(self) -> Self::Inner {
681 (
682 (self.buffer, self.control),
683 self.addr,
684 self.msg.msg_namelen,
685 self.msg.msg_controllen as _,
686 )
687 }
688}
689
690pin_project! {
691 pub struct SendMsg<T: IoVectoredBuf, C: IoBuf, S> {
694 pub(crate) msg: libc::msghdr,
695 pub(crate) fd: S,
696 #[pin]
697 pub(crate) buffer: T,
698 #[pin]
699 pub(crate) control: C,
700 pub(crate) addr: SockAddr,
701 pub(crate) slices: Vec<SysSlice>,
702 pub(crate) flags: i32,
703 _p: PhantomPinned,
704 }
705}
706
707impl<T: IoVectoredBuf, C: IoBuf, S> SendMsg<T, C, S> {
708 pub fn new(fd: S, buffer: T, control: C, addr: SockAddr, flags: i32) -> Self {
714 assert!(
715 control.buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
716 "misaligned control message buffer"
717 );
718 Self {
719 msg: unsafe { std::mem::zeroed() },
720 fd,
721 buffer,
722 control,
723 addr,
724 slices: vec![],
725 flags,
726 _p: PhantomPinned,
727 }
728 }
729
730 pub(crate) fn set_msg(self: Pin<&mut Self>) {
731 let this = self.project();
732 *this.slices = this.buffer.as_ref().sys_slices();
733 this.msg.msg_name = this.addr.as_ptr() as _;
734 this.msg.msg_namelen = this.addr.len();
735 this.msg.msg_iov = this.slices.as_ptr() as _;
736 this.msg.msg_iovlen = this.slices.len() as _;
737 this.msg.msg_control = this.control.buf_ptr() as _;
738 this.msg.msg_controllen = this.control.buf_len() as _;
739 }
740}
741
742impl<T: IoVectoredBuf, C: IoBuf, S> IntoInner for SendMsg<T, C, S> {
743 type Inner = (T, C);
744
745 fn into_inner(self) -> Self::Inner {
746 (self.buffer, self.control)
747 }
748}
749
750#[derive(Debug, Clone, Copy, PartialEq, Eq)]
752pub enum Interest {
753 Readable,
755 Writable,
757}
758
759pub struct PollOnce<S> {
761 pub(crate) fd: S,
762 pub(crate) interest: Interest,
763}
764
765impl<S> PollOnce<S> {
766 pub fn new(fd: S, interest: Interest) -> Self {
768 Self { fd, interest }
769 }
770}
771
772#[cfg(linux_all)]
774pub struct Splice<S1, S2> {
775 pub(crate) fd_in: S1,
776 pub(crate) offset_in: i64,
777 pub(crate) fd_out: S2,
778 pub(crate) offset_out: i64,
779 pub(crate) len: usize,
780 pub(crate) flags: u32,
781}
782
783#[cfg(linux_all)]
784impl<S1, S2> Splice<S1, S2> {
785 pub fn new(
791 fd_in: S1,
792 offset_in: i64,
793 fd_out: S2,
794 offset_out: i64,
795 len: usize,
796 flags: u32,
797 ) -> Self {
798 Self {
799 fd_in,
800 offset_in,
801 fd_out,
802 offset_out,
803 len,
804 flags,
805 }
806 }
807}