1 use crate::host;
2 use std::fs::File;
3 use std::os::unix::prelude::{FileTypeExt, FromRawFd, IntoRawFd, RawFd};
4 use std::path::PathBuf;
5
6 #[derive(Debug)]
7 pub struct FdEntry {
8 pub fd_object: FdObject,
9 pub rights_base: host::__wasi_rights_t,
10 pub rights_inheriting: host::__wasi_rights_t,
11 pub preopen_path: Option<PathBuf>,
12 }
13
14 impl FdEntry {
from_file(file: File) -> FdEntry15 pub fn from_file(file: File) -> FdEntry {
16 unsafe { FdEntry::from_raw_fd(file.into_raw_fd()) }
17 }
from_raw_fd_for_io_desc(rawfd: RawFd, writable : bool) -> FdEntry18 pub unsafe fn from_raw_fd_for_io_desc(rawfd: RawFd, writable : bool) -> FdEntry {
19 let (ty, mut rights_base, rights_inheriting) =
20 (
21 host::__WASI_FILETYPE_CHARACTER_DEVICE,
22 host::RIGHTS_TTY_BASE,
23 host::RIGHTS_TTY_BASE,
24 );
25
26 if !writable {
27 rights_base &= !host::__WASI_RIGHT_FD_WRITE as host::__wasi_rights_t;
28 } else {
29 rights_base &= !host::__WASI_RIGHT_FD_READ as host::__wasi_rights_t;
30 }
31
32 FdEntry {
33 fd_object: FdObject {
34 ty: ty as u8,
35 rawfd,
36 needs_close: true,
37 },
38 rights_base,
39 rights_inheriting,
40 preopen_path: None,
41 }
42 }
43
44 }
45
46 impl FromRawFd for FdEntry {
47 // TODO: make this a different function with error handling, rather than using the trait method
from_raw_fd(rawfd: RawFd) -> FdEntry48 unsafe fn from_raw_fd(rawfd: RawFd) -> FdEntry {
49 let (ty, mut rights_base, rights_inheriting) =
50 determine_type_rights(rawfd).expect("can determine file rights");
51
52 use nix::fcntl::{fcntl, OFlag, F_GETFL};
53 let flags_bits = fcntl(rawfd, F_GETFL).expect("fcntl succeeds");
54 let flags = OFlag::from_bits_truncate(flags_bits);
55 let accmode = flags & OFlag::O_ACCMODE;
56 if accmode == OFlag::O_RDONLY {
57 rights_base &= !host::__WASI_RIGHT_FD_WRITE as host::__wasi_rights_t;
58 } else if accmode == OFlag::O_WRONLY {
59 rights_base &= !host::__WASI_RIGHT_FD_READ as host::__wasi_rights_t;
60 }
61
62 FdEntry {
63 fd_object: FdObject {
64 ty: ty as u8,
65 rawfd,
66 needs_close: true,
67 },
68 rights_base,
69 rights_inheriting,
70 preopen_path: None,
71 }
72 }
73 }
74
75 // TODO: can probably make this safe by using fcntl directly rather than going through `File`
determine_type_rights( rawfd: RawFd, ) -> Result< ( host::__wasi_filetype_t, host::__wasi_rights_t, host::__wasi_rights_t, ), host::__wasi_errno_t, >76 pub unsafe fn determine_type_rights(
77 rawfd: RawFd,
78 ) -> Result<
79 (
80 host::__wasi_filetype_t,
81 host::__wasi_rights_t,
82 host::__wasi_rights_t,
83 ),
84 host::__wasi_errno_t,
85 > {
86 let (ty, rights_base, rights_inheriting) = {
87 let file = File::from_raw_fd(rawfd);
88 let ft = file.metadata().unwrap().file_type();
89 // we just make a `File` here for convenience; we don't want it to close when it drops
90 std::mem::forget(file);
91 if ft.is_block_device() {
92 (
93 host::__WASI_FILETYPE_BLOCK_DEVICE,
94 host::RIGHTS_BLOCK_DEVICE_BASE,
95 host::RIGHTS_BLOCK_DEVICE_INHERITING,
96 )
97 } else if ft.is_char_device() {
98 if nix::unistd::isatty(rawfd).unwrap() {
99 (
100 host::__WASI_FILETYPE_CHARACTER_DEVICE,
101 host::RIGHTS_TTY_BASE,
102 host::RIGHTS_TTY_BASE,
103 )
104 } else {
105 (
106 host::__WASI_FILETYPE_CHARACTER_DEVICE,
107 host::RIGHTS_CHARACTER_DEVICE_BASE,
108 host::RIGHTS_CHARACTER_DEVICE_INHERITING,
109 )
110 }
111 } else if ft.is_dir() {
112 (
113 host::__WASI_FILETYPE_DIRECTORY,
114 host::RIGHTS_DIRECTORY_BASE,
115 host::RIGHTS_DIRECTORY_INHERITING,
116 )
117 } else if ft.is_file() {
118 (
119 host::__WASI_FILETYPE_REGULAR_FILE,
120 host::RIGHTS_REGULAR_FILE_BASE,
121 host::RIGHTS_REGULAR_FILE_INHERITING,
122 )
123 // } else if ft.is_socket() {
124 // use nix::sys::socket;
125 // match socket::getsockopt(rawfd, socket::sockopt::SockType).unwrap() {
126 // socket::SockType::Datagram => (
127 // host::__WASI_FILETYPE_SOCKET_DGRAM,
128 // host::RIGHTS_SOCKET_BASE,
129 // host::RIGHTS_SOCKET_INHERITING,
130 // ),
131 // socket::SockType::Stream => (
132 // host::__WASI_FILETYPE_SOCKET_STREAM,
133 // host::RIGHTS_SOCKET_BASE,
134 // host::RIGHTS_SOCKET_INHERITING,
135 // ),
136 // _ => return Err(host::__WASI_EINVAL as host::__wasi_errno_t),
137 // }
138 } else if ft.is_fifo() {
139 (
140 host::__WASI_FILETYPE_SOCKET_STREAM,
141 host::RIGHTS_SOCKET_BASE,
142 host::RIGHTS_SOCKET_INHERITING,
143 )
144 } else {
145 return Err(host::__WASI_EINVAL as host::__wasi_errno_t);
146 }
147 };
148 Ok((
149 ty as host::__wasi_filetype_t,
150 rights_base,
151 rights_inheriting,
152 ))
153 }
154
155 #[derive(Debug)]
156 pub struct FdObject {
157 pub ty: host::__wasi_filetype_t,
158 pub rawfd: RawFd,
159 pub needs_close: bool,
160 // TODO: directories
161 }
162
163 impl Drop for FdObject {
drop(&mut self)164 fn drop(&mut self) {
165 if self.needs_close {
166 nix::unistd::close(self.rawfd).unwrap_or_else(|e| eprintln!("FdObject::drop(): {}", e));
167 }
168 }
169 }
170