1#[cfg(any(fuchsia_api_level_at_least = "PLATFORM", not(fuchsia_api_level_at_least = "32")))]
8use crate::common::stricter_or_same_rights;
9use crate::directory::entry::EntryInfo;
10
11use flex_fuchsia_io as fio;
12use static_assertions::assert_eq_size;
13use std::mem::size_of;
14#[cfg(any(fuchsia_api_level_at_least = "PLATFORM", not(fuchsia_api_level_at_least = "32")))]
15use zx_status::Status;
16
17#[cfg(any(fuchsia_api_level_at_least = "PLATFORM", not(fuchsia_api_level_at_least = "32")))]
22pub(crate) fn check_child_connection_flags(
23 parent_flags: fio::OpenFlags,
24 mut flags: fio::OpenFlags,
25) -> Result<fio::OpenFlags, Status> {
26 if flags & (fio::OpenFlags::NOT_DIRECTORY | fio::OpenFlags::DIRECTORY)
27 == fio::OpenFlags::NOT_DIRECTORY | fio::OpenFlags::DIRECTORY
28 {
29 return Err(Status::INVALID_ARGS);
30 }
31
32 if flags.intersects(fio::OpenFlags::CREATE_IF_ABSENT)
34 && !flags.intersects(fio::OpenFlags::CREATE)
35 {
36 return Err(Status::INVALID_ARGS);
37 }
38
39 if flags.intersects(fio::OpenFlags::CLONE_SAME_RIGHTS) {
41 return Err(Status::INVALID_ARGS);
42 }
43
44 if !parent_flags.intersects(fio::OpenFlags::RIGHT_EXECUTABLE) {
46 flags &= !fio::OpenFlags::POSIX_EXECUTABLE;
47 }
48 if !parent_flags.intersects(fio::OpenFlags::RIGHT_WRITABLE) {
49 flags &= !fio::OpenFlags::POSIX_WRITABLE;
50 }
51
52 if flags.intersects(fio::OpenFlags::CREATE)
54 && !parent_flags.intersects(fio::OpenFlags::RIGHT_WRITABLE)
55 {
56 return Err(Status::ACCESS_DENIED);
57 }
58
59 if stricter_or_same_rights(parent_flags, flags) {
60 Ok(flags)
61 } else {
62 Err(Status::ACCESS_DENIED)
63 }
64}
65
66pub(crate) fn encode_dirent(
71 buf: &mut Vec<u8>,
72 max_bytes: u64,
73 entry: &EntryInfo,
74 name: &str,
75) -> bool {
76 const HEADER_SIZE: usize = size_of::<u64>() + size_of::<u8>() + size_of::<u8>();
77
78 assert_eq_size!(u64, usize);
79
80 if buf.len() + HEADER_SIZE + name.len() > max_bytes as usize {
81 return false;
82 }
83
84 assert!(
87 name.len() <= fio::MAX_NAME_LENGTH as usize,
88 "Entry names are expected to be no longer than MAX_FILENAME ({}) bytes.\n\
89 Got entry: '{}'\n\
90 Length: {} bytes",
91 fio::MAX_NAME_LENGTH,
92 name,
93 name.len()
94 );
95
96 assert!(
97 fio::MAX_NAME_LENGTH <= u8::MAX as u64,
98 "Expecting to be able to store MAX_FILENAME ({}) in one byte.",
99 fio::MAX_NAME_LENGTH
100 );
101 buf.reserve(HEADER_SIZE + name.len());
102 buf.extend_from_slice(&entry.inode().to_le_bytes());
103 buf.push(name.len() as u8);
104 buf.push(entry.type_().into_primitive());
105 buf.extend_from_slice(name.as_bytes());
106
107 true
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[cfg(any(fuchsia_api_level_at_least = "PLATFORM", not(fuchsia_api_level_at_least = "32")))]
115 #[fuchsia::test]
116 fn test_check_child_connection_flags() {
117 let rw_parent = fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE;
118 let ro_parent = fio::OpenFlags::RIGHT_READABLE;
119
120 assert_eq!(
122 check_child_connection_flags(
123 rw_parent,
124 fio::OpenFlags::DIRECTORY | fio::OpenFlags::NOT_DIRECTORY
125 ),
126 Err(Status::INVALID_ARGS)
127 );
128
129 assert_eq!(
131 check_child_connection_flags(rw_parent, fio::OpenFlags::CREATE_IF_ABSENT),
132 Err(Status::INVALID_ARGS)
133 );
134
135 assert_eq!(
137 check_child_connection_flags(rw_parent, fio::OpenFlags::CLONE_SAME_RIGHTS),
138 Err(Status::INVALID_ARGS)
139 );
140
141 assert_eq!(
143 check_child_connection_flags(
144 ro_parent,
145 fio::OpenFlags::RIGHT_READABLE
146 | fio::OpenFlags::POSIX_WRITABLE
147 | fio::OpenFlags::POSIX_EXECUTABLE
148 ),
149 Ok(fio::OpenFlags::RIGHT_READABLE)
150 );
151
152 assert_eq!(
154 check_child_connection_flags(ro_parent, fio::OpenFlags::CREATE),
155 Err(Status::ACCESS_DENIED)
156 );
157
158 assert_eq!(
160 check_child_connection_flags(ro_parent, fio::OpenFlags::RIGHT_WRITABLE),
161 Err(Status::ACCESS_DENIED)
162 );
163
164 assert_eq!(
166 check_child_connection_flags(
167 rw_parent,
168 fio::OpenFlags::CREATE
169 | fio::OpenFlags::CREATE_IF_ABSENT
170 | fio::OpenFlags::RIGHT_WRITABLE
171 ),
172 Ok(fio::OpenFlags::CREATE
173 | fio::OpenFlags::CREATE_IF_ABSENT
174 | fio::OpenFlags::RIGHT_WRITABLE)
175 );
176 }
177
178 #[fuchsia::test]
179 fn test_encode_dirent() {
180 let entry = EntryInfo::new(42, fio::DirentType::File);
181 let mut buf = Vec::new();
182
183 assert!(!encode_dirent(&mut buf, 10, &entry, "hello"));
185 assert!(buf.is_empty());
186
187 assert!(encode_dirent(&mut buf, 15, &entry, "hello"));
189 assert_eq!(buf.len(), 15);
190 assert_eq!(&buf[0..8], &42u64.to_le_bytes());
191 assert_eq!(buf[8], 5);
192 assert_eq!(buf[9], fio::DirentType::File.into_primitive());
193 assert_eq!(&buf[10..15], b"hello");
194 }
195}