1use core::str;
2use std::{
3 path::{Component, Path, PathBuf},
4 sync::Arc,
5};
6
7use bitflags::bitflags;
8use ext::ExtNamespace;
9use nsobj::NamespaceObject;
10use object_store::objid_to_ino;
11use twizzler::marker::Invariant;
12use twizzler_rt_abi::{
13 error::{ArgumentError, GenericError, NamingError},
14 object::ObjID,
15};
16
17use crate::{Result, MAX_KEY_SIZE};
18
19mod ext;
20mod nsobj;
21
22#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
23#[repr(C)]
24pub enum NsNodeKind {
25 Namespace,
26 Object,
27 SymLink,
28}
29unsafe impl Invariant for NsNodeKind {}
30
31const NSID_EXTERNAL: ObjID = ObjID::new(1);
32
33#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, twizzler::Invariant)]
34#[repr(C)]
35pub struct NsNode {
36 name: [u8; MAX_KEY_SIZE],
37 pub id: ObjID,
38 pub kind: NsNodeKind,
39 name_len: u32,
40 link_len: u32,
41}
42
43impl NsNode {
44 pub fn new<P: AsRef<Path>, L: AsRef<Path>>(
45 kind: NsNodeKind,
46 id: ObjID,
47 name: P,
48 link_name: Option<L>,
49 ) -> Result<Self> {
50 let name = name.as_ref().as_os_str().as_encoded_bytes();
51 Ok(if let Some(link_name) = link_name {
52 let lname = link_name.as_ref().as_os_str().as_encoded_bytes();
53 if lname.len() + name.len() > MAX_KEY_SIZE {
54 return Err(ArgumentError::InvalidArgument.into());
55 }
56 let mut cname = [0; MAX_KEY_SIZE];
57 cname[0..name.len()].copy_from_slice(&name);
58 cname[name.len()..(name.len() + lname.len())].clone_from_slice(&lname);
59 Self {
60 kind: NsNodeKind::SymLink,
61 name: cname,
62 id,
63 name_len: name.len() as u32,
64 link_len: lname.len() as u32,
65 }
66 } else {
67 let mut cname = [0; MAX_KEY_SIZE];
68 cname[0..name.len()].copy_from_slice(&name);
69 Self {
70 kind,
71 id,
72 name: cname,
73 name_len: name.len() as u32,
74 link_len: 0,
75 }
76 })
77 }
78
79 pub fn ns<P: AsRef<Path>>(name: P, id: ObjID) -> Result<Self> {
80 Self::new::<_, P>(NsNodeKind::Namespace, id, name, None)
81 }
82
83 pub fn obj<P: AsRef<Path>>(name: P, id: ObjID) -> Result<Self> {
84 Self::new::<_, P>(NsNodeKind::Object, id, name, None)
85 }
86
87 pub fn symlink<P: AsRef<Path>, L: AsRef<Path>>(name: P, lname: L) -> Result<Self> {
88 Self::new(NsNodeKind::SymLink, 0.into(), name, Some(lname))
89 }
90
91 pub fn name(&self) -> Result<&str> {
92 let bytes = &self.name[0..(self.name_len as usize)];
93 str::from_utf8(bytes).map_err(|_| GenericError::Internal.into())
94 }
95
96 pub fn readlink(&self) -> Result<&str> {
97 if self.kind != NsNodeKind::SymLink {
98 return Err(NamingError::WrongNameKind.into());
99 }
100 let bytes =
101 &self.name[(self.name_len as usize)..(self.name_len as usize + self.link_len as usize)];
102 str::from_utf8(bytes).map_err(|_| GenericError::Internal.into())
103 }
104}
105
106#[derive(Clone)]
107struct ParentInfo {
108 ns: Arc<dyn Namespace>,
109 name_in_parent: String,
110}
111
112impl ParentInfo {
113 fn new(ns: Arc<dyn Namespace>, name_in_parent: impl ToString) -> Self {
114 Self {
115 ns,
116 name_in_parent: name_in_parent.to_string(),
117 }
118 }
119}
120
121trait Namespace {
122 fn open(id: ObjID, persist: bool, parent_info: Option<ParentInfo>) -> Result<Self>
123 where
124 Self: Sized;
125
126 fn find(&self, name: &str) -> Option<NsNode>;
127
128 fn insert(&self, node: NsNode) -> Option<NsNode>;
129
130 fn remove(&self, name: &str) -> Option<NsNode>;
131
132 fn parent(&self) -> Option<&ParentInfo>;
133
134 fn id(&self) -> ObjID;
135
136 fn items(&self) -> Vec<NsNode>;
137
138 #[allow(dead_code)]
139 fn len(&self) -> usize {
140 self.items().len()
141 }
142
143 fn persist(&self) -> bool;
144}
145
146pub struct NameStore {
147 nameroot: Arc<dyn Namespace>,
148 dataroot: ObjID,
149}
150
151unsafe impl Send for NameStore {}
152unsafe impl Sync for NameStore {}
153
154impl NameStore {
155 pub fn new() -> NameStore {
156 let this = NameStore {
157 nameroot: Arc::new(NamespaceObject::new(false, None, None).unwrap()),
158 dataroot: 0.into(),
159 };
160 this.nameroot
161 .insert(NsNode::ns("ext", NSID_EXTERNAL).unwrap());
162 this
163 }
164
165 pub fn new_with(id: ObjID) -> Result<NameStore> {
167 let mut this = Self::new();
168 this.nameroot.insert(NsNode::ns("data", id).unwrap());
169 this.dataroot = id;
170 tracing::debug!(
171 "new_with: data={}, data={:?}, root={}",
172 id,
173 this.nameroot.find("data"),
174 this.id()
175 );
176 Ok(this)
177 }
178
179 pub fn new_with_root(id: ObjID) -> Result<NameStore> {
181 let namespace = NamespaceObject::open(id, false, None)?;
182 Ok(Self {
183 nameroot: Arc::new(namespace),
184 dataroot: id,
185 })
186 }
187
188 pub fn id(&self) -> ObjID {
189 self.nameroot.id()
190 }
191
192 pub fn new_session(&self, namespace: &Path) -> NameSession<'_> {
194 let mut path = PathBuf::from("/");
195 path.extend(namespace);
196 let mut this = NameSession {
197 store: self,
198 working_ns: None,
199 };
200 this.change_namespace(namespace).unwrap();
201 this
202 }
203
204 pub fn root_session(&self) -> NameSession<'_> {
205 NameSession {
206 store: self,
207 working_ns: None,
208 }
209 }
210}
211
212pub struct NameSession<'a> {
213 store: &'a NameStore,
214 working_ns: Option<Arc<dyn Namespace>>,
215}
216
217impl NameSession<'_> {
218 pub const MAX_SYMLINK_DEREF: usize = 32;
219 fn open_namespace(
220 &self,
221 id: ObjID,
222 persist: bool,
223 parent_info: Option<ParentInfo>,
224 ) -> Result<Arc<dyn Namespace>> {
225 let is_dataroot = id == self.store.dataroot;
226 Ok(if id == NSID_EXTERNAL || objid_to_ino(id.raw()).is_some() {
227 Arc::new(ExtNamespace::open(id, persist, parent_info)?)
228 } else {
229 Arc::new(NamespaceObject::open(
230 id,
231 persist || is_dataroot,
232 parent_info,
233 )?)
234 })
235 }
236
237 fn namei<P: AsRef<Path>>(
240 &self,
241 namespace: Option<Arc<dyn Namespace>>,
242 name: P,
243 nr_derefs: usize,
244 deref: bool,
245 ) -> Result<(std::result::Result<NsNode, PathBuf>, Arc<dyn Namespace>)> {
246 tracing::trace!("namei: {:?}", name.as_ref());
247
248 let mut namespace = namespace.unwrap_or_else(|| {
249 self.working_ns
250 .as_ref()
251 .unwrap_or(&self.store.nameroot)
252 .clone()
253 });
254
255 let components = name.as_ref().components().collect::<Vec<_>>();
256 if components.is_empty() {
257 return Ok((Err("".into()), namespace));
258 }
259
260 let mut node = None;
261 for (idx, item) in components.iter().enumerate() {
262 let is_last = idx == components.len() - 1;
263 match item {
264 Component::Prefix(_) => continue,
265 Component::RootDir => {
266 namespace = self.store.nameroot.clone();
267 node = Some(NsNode::ns("/", namespace.id())?);
268 }
269 Component::CurDir => {
270 node = namespace.find(".");
271 }
272 Component::ParentDir => {
273 if let Some(parent) = namespace.parent() {
274 node = Some(NsNode::ns(&parent.name_in_parent, parent.ns.id())?);
275 namespace = parent.ns.clone();
276 } else {
277 node = Some(namespace.find("..").ok_or(NamingError::NotFound)?);
278 let parent_info = ParentInfo::new(namespace, "..");
279 namespace = self.open_namespace(
280 node.as_ref().unwrap().id,
281 parent_info.ns.persist(),
282 Some(parent_info),
283 )?;
284 }
285 }
286 Component::Normal(os_str) => {
287 tracing::trace!(
288 "lookup component {:?}: {}",
289 os_str.as_encoded_bytes(),
290 os_str.to_str().ok_or(ArgumentError::InvalidArgument)?
291 );
292 node = namespace.find(os_str.to_str().ok_or(ArgumentError::InvalidArgument)?);
293
294 let Some(thisnode) = node else {
296 tracing::trace!("failed to find component: (is_last = {})", is_last);
297 if is_last {
299 return Ok((Err(os_str.into()), namespace));
300 } else {
301 return Err(NamingError::NotFound.into());
302 }
303 };
304 if thisnode.kind == NsNodeKind::SymLink {
306 tracing::trace!("found symlink: {} {} {}", nr_derefs, deref, is_last);
307 if nr_derefs == 0 {
308 return Err(NamingError::LinkLoop.into());
309 }
310 if deref || !is_last {
311 let ldname = thisnode.readlink()?;
312 tracing::trace!("search with: {}", ldname);
313 let (lnode, lcont) =
314 self.namei_exist(Some(namespace), ldname, nr_derefs - 1, deref)?;
315 node = Some(lnode);
316 namespace = lcont;
317 }
318 }
319 if !is_last && thisnode.kind == NsNodeKind::Namespace {
320 let parent_info = ParentInfo::new(namespace, thisnode.name()?);
321 namespace = self.open_namespace(
322 thisnode.id,
323 parent_info.ns.persist(),
324 Some(parent_info),
325 )?;
326 }
327 }
328 }
329 }
330
331 if let Some(node) = node {
332 Ok((Ok(node), namespace))
333 } else {
334 Ok((
336 Err(components.last().unwrap().as_os_str().into()),
337 namespace,
338 ))
339 }
340 }
341
342 fn namei_exist<'a, P: AsRef<Path>>(
343 &self,
344 namespace: Option<Arc<dyn Namespace>>,
345 name: P,
346 nr_derefs: usize,
347 deref: bool,
348 ) -> Result<(NsNode, Arc<dyn Namespace>)> {
349 let (n, ns) = self.namei(namespace, name, nr_derefs, deref)?;
350 Ok((n.ok().ok_or(NamingError::NotFound)?, ns))
351 }
352
353 pub fn mkns<P: AsRef<Path>>(&self, name: P, persist: bool) -> Result<()> {
354 let (node, container) = self.namei(None, &name, Self::MAX_SYMLINK_DEREF, false)?;
355 let Err(name) = node else {
356 return Err(NamingError::AlreadyExists.into());
357 };
358 let ns = NamespaceObject::new(
359 persist,
360 Some(container.id()),
361 Some(ParentInfo::new(
362 container.clone(),
363 name.display().to_string(),
364 )),
365 )?;
366 container.insert(NsNode::ns(name, ns.id())?);
367 Ok(())
368 }
369
370 pub fn put<P: AsRef<Path>>(&self, name: P, id: ObjID) -> Result<()> {
371 tracing::debug!("put {:?}: {}", name.as_ref(), id);
372 let (node, container) = self.namei(None, &name, Self::MAX_SYMLINK_DEREF, false)?;
373 let Err(name) = node else {
374 return Err(NamingError::AlreadyExists.into());
375 };
376
377 container.insert(NsNode::obj(name, id)?);
378 Ok(())
379 }
380
381 pub fn get<P: AsRef<Path>>(&self, name: P, flags: GetFlags) -> Result<NsNode> {
382 tracing::debug!("get {:?}: {:?}", name.as_ref(), flags);
383 let (node, _) = self.namei_exist(
384 None,
385 name,
386 Self::MAX_SYMLINK_DEREF,
387 flags.contains(GetFlags::FOLLOW_SYMLINK),
388 )?;
389 Ok(node)
390 }
391
392 pub fn enumerate_namespace<P: AsRef<Path>>(&self, name: P) -> Result<std::vec::Vec<NsNode>> {
393 tracing::trace!("enumerate: {:?}", name.as_ref());
394 let (node, container) = self.namei_exist(None, name, Self::MAX_SYMLINK_DEREF, true)?;
395 if node.kind != NsNodeKind::Namespace {
396 return Err(NamingError::WrongNameKind.into());
397 }
398 tracing::trace!("opening namespace: {}", node.id);
399 let ns = self.open_namespace(
400 node.id,
401 false,
402 Some(ParentInfo::new(container, node.name()?)),
403 )?;
404 let items = ns.items();
405 tracing::trace!("collected: {:?}", items);
406 Ok(items)
407 }
408
409 pub fn enumerate_namespace_nsid(&self, id: ObjID) -> Result<std::vec::Vec<NsNode>> {
410 tracing::trace!("opening namespace-ensid: {}", id);
411 let ns = self.open_namespace(id, false, None)?;
412 let items = ns.items();
413 tracing::trace!("collected: {:?}", items);
414 Ok(items)
415 }
416
417 pub fn change_namespace<P: AsRef<Path>>(&mut self, name: P) -> Result<()> {
418 tracing::debug!("change_ns: {:?}", name.as_ref());
419 let (node, container) = self.namei_exist(None, name, Self::MAX_SYMLINK_DEREF, true)?;
420 match node.kind {
421 NsNodeKind::Namespace => {
422 self.working_ns = Some(self.open_namespace(
423 node.id,
424 container.persist(),
425 Some(ParentInfo::new(container, node.name()?)),
426 )?);
427 Ok(())
428 }
429 _ => Err(NamingError::WrongNameKind.into()),
430 }
431 }
432
433 pub fn remove<P: AsRef<Path>>(&self, name: P) -> Result<()> {
434 let (node, container) = self.namei_exist(None, &name, Self::MAX_SYMLINK_DEREF, false)?;
435 container
436 .remove(node.name()?)
437 .map(|_| ())
438 .ok_or(NamingError::NotFound.into())
439 }
440
441 pub fn link<P: AsRef<Path>, L: AsRef<Path>>(&self, name: P, link: L) -> Result<()> {
442 let (node, container) = self.namei(None, &name, Self::MAX_SYMLINK_DEREF, false)?;
443 let Err(name) = node else {
444 return Err(NamingError::AlreadyExists.into());
445 };
446
447 container.insert(NsNode::symlink(name, link)?);
448 Ok(())
449 }
450
451 pub fn readlink<P: AsRef<Path>>(&self, name: P) -> Result<PathBuf> {
452 let (node, _) = self.namei_exist(None, name, Self::MAX_SYMLINK_DEREF, false)?;
453 node.readlink().map(PathBuf::from)
454 }
455}
456
457bitflags! {
458 #[derive(Clone, Copy, Default, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
459 pub struct GetFlags: u32 {
460 const FOLLOW_SYMLINK = 1;
461 }
462}