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 pager_dynamic::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, skip: usize, count: usize) -> Vec<NsNode>;
137
138 #[allow(dead_code)]
139 fn len(&self) -> usize {
140 self.items(0, usize::MAX).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 mut 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 tracing::trace!("start search {}", name.as_ref().display());
260
261 let mut node = None;
262 for (idx, item) in components.iter().enumerate() {
263 let is_last = idx == components.len() - 1;
264 match item {
265 Component::Prefix(_) => continue,
266 Component::RootDir => {
267 namespace = self.store.nameroot.clone();
268 node = Some(NsNode::ns("/", namespace.id())?);
269 }
270 Component::CurDir => {
271 node = namespace.find(".");
272 }
273 Component::ParentDir => {
274 if let Some(parent) = namespace.parent() {
275 node = Some(NsNode::ns(&parent.name_in_parent, parent.ns.id())?);
276 namespace = parent.ns.clone();
277 } else {
278 node = Some(namespace.find("..").ok_or(NamingError::NotFound)?);
279 let parent_info = ParentInfo::new(namespace, "..");
280 namespace = self.open_namespace(
281 node.as_ref().unwrap().id,
282 parent_info.ns.persist(),
283 Some(parent_info),
284 )?;
285 }
286 }
287 Component::Normal(os_str) => {
288 tracing::trace!(
289 "lookup component {} in {}",
290 os_str.to_str().ok_or(ArgumentError::InvalidArgument)?,
291 namespace.id(),
292 );
293 node = namespace.find(os_str.to_str().ok_or(ArgumentError::InvalidArgument)?);
294 let name = node.as_ref().map(|x| x.name());
295 tracing::trace!("found node: {:?} (is_last = {})", name, is_last);
296
297 let Some(mut thisnode) = node else {
299 tracing::trace!(
300 "failed to find component {:?}: (is_last = {})",
301 os_str.to_str(),
302 is_last
303 );
304 if is_last {
306 return Ok((Err(os_str.into()), namespace));
307 } else {
308 return Err(NamingError::NotFound.into());
309 }
310 };
311 if thisnode.kind == NsNodeKind::SymLink {
313 tracing::trace!("found symlink: {} {} {}", nr_derefs, deref, is_last);
314 if nr_derefs == 0 {
315 return Err(NamingError::LinkLoop.into());
316 }
317 if deref || !is_last {
318 let mut lcont = None;
319 while thisnode.kind == NsNodeKind::SymLink {
320 let ldname = thisnode.readlink()?;
321 tracing::trace!("search with: {}", ldname);
322 nr_derefs -= 1;
323 let (lnode, lc) = self.namei_exist(
324 Some(namespace.clone()),
325 ldname,
326 nr_derefs,
327 deref,
328 )?;
329 tracing::trace!("found lnode as {:?}", lnode);
330 node = Some(lnode);
331 thisnode = lnode;
332 lcont = Some(lc);
333 }
334 if !is_last {
335 namespace = self.open_namespace(
336 thisnode.id,
337 lcont.as_ref().unwrap().persist(),
338 Some(ParentInfo {
339 ns: lcont.unwrap(),
340 name_in_parent: thisnode.name()?.to_string(),
341 }),
342 )?;
343 }
344 }
345 }
346 if !is_last && thisnode.kind == NsNodeKind::Namespace {
347 let parent_info = ParentInfo::new(namespace, thisnode.name()?);
348 namespace = self.open_namespace(
349 thisnode.id,
350 parent_info.ns.persist(),
351 Some(parent_info),
352 )?;
353 }
354 }
355 }
356 }
357 tracing::trace!("namei result: {:?}", node);
358
359 if let Some(node) = node {
360 Ok((Ok(node), namespace))
361 } else {
362 Ok((
364 Err(components.last().unwrap().as_os_str().into()),
365 namespace,
366 ))
367 }
368 }
369
370 fn namei_exist<'a, P: AsRef<Path>>(
371 &self,
372 namespace: Option<Arc<dyn Namespace>>,
373 name: P,
374 nr_derefs: usize,
375 deref: bool,
376 ) -> Result<(NsNode, Arc<dyn Namespace>)> {
377 let (n, ns) = self.namei(namespace, name, nr_derefs, deref)?;
378 Ok((n.ok().ok_or(NamingError::NotFound)?, ns))
379 }
380
381 pub fn mkns<P: AsRef<Path>>(&self, name: P, persist: bool) -> Result<()> {
382 let (node, container) = self.namei(None, &name, Self::MAX_SYMLINK_DEREF, false)?;
383 let Err(name) = node else {
384 return Err(NamingError::AlreadyExists.into());
385 };
386 let ns = NamespaceObject::new(
387 persist,
388 Some(container.id()),
389 Some(ParentInfo::new(
390 container.clone(),
391 name.display().to_string(),
392 )),
393 )?;
394 container.insert(NsNode::ns(name, ns.id())?);
395 Ok(())
396 }
397
398 pub fn put<P: AsRef<Path>>(&self, name: P, id: ObjID) -> Result<()> {
399 tracing::debug!("put {:?}: {}", name.as_ref(), id);
400 let (node, container) = self.namei(None, &name, Self::MAX_SYMLINK_DEREF, false)?;
401 let Err(name) = node else {
402 return Err(NamingError::AlreadyExists.into());
403 };
404
405 container.insert(NsNode::obj(name, id)?);
406 Ok(())
407 }
408
409 pub fn get<P: AsRef<Path>>(&self, name: P, flags: GetFlags) -> Result<NsNode> {
410 tracing::debug!("get {:?}: {:?}", name.as_ref(), flags);
411 let (node, _) = self.namei_exist(
412 None,
413 name,
414 Self::MAX_SYMLINK_DEREF,
415 flags.contains(GetFlags::FOLLOW_SYMLINK),
416 )?;
417 Ok(node)
418 }
419
420 pub fn enumerate_namespace<P: AsRef<Path>>(
421 &self,
422 name: P,
423 skip: usize,
424 count: usize,
425 ) -> Result<std::vec::Vec<NsNode>> {
426 tracing::trace!("enumerate: {:?}", name.as_ref());
427 let (node, container) = self.namei_exist(None, name, Self::MAX_SYMLINK_DEREF, true)?;
428 if node.kind != NsNodeKind::Namespace {
429 return Err(NamingError::WrongNameKind.into());
430 }
431 tracing::trace!("opening namespace: {}", node.id);
432 let ns = self.open_namespace(
433 node.id,
434 false,
435 Some(ParentInfo::new(container, node.name()?)),
436 )?;
437 let items = ns.items(skip, count);
438 tracing::trace!("collected: {:?}", items);
439 Ok(items)
440 }
441
442 pub fn enumerate_namespace_nsid(
443 &self,
444 id: ObjID,
445 skip: usize,
446 count: usize,
447 ) -> Result<std::vec::Vec<NsNode>> {
448 tracing::trace!("opening namespace-ensid: {} {} {}", id, skip, count);
449 let ns = self.open_namespace(id, false, None)?;
450 let items = ns.items(skip, count);
451 tracing::trace!("collected: {:?}", items);
452 Ok(items)
453 }
454
455 pub fn change_namespace<P: AsRef<Path>>(&mut self, name: P) -> Result<()> {
456 tracing::trace!("change_ns: {:?}", name.as_ref());
457 let (node, container) = self.namei_exist(None, name, Self::MAX_SYMLINK_DEREF, true)?;
458 match node.kind {
459 NsNodeKind::Namespace => {
460 self.working_ns = Some(self.open_namespace(
461 node.id,
462 container.persist(),
463 Some(ParentInfo::new(container, node.name()?)),
464 )?);
465 Ok(())
466 }
467 _ => Err(NamingError::WrongNameKind.into()),
468 }
469 }
470
471 pub fn remove<P: AsRef<Path>>(&self, name: P) -> Result<()> {
472 let (node, container) = self.namei_exist(None, &name, Self::MAX_SYMLINK_DEREF, false)?;
473 container
474 .remove(node.name()?)
475 .map(|_| ())
476 .ok_or(NamingError::NotFound.into())
477 }
478
479 pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, old: P, new: Q) -> Result<()> {
480 tracing::trace!("rename: {:?} to {:?}", old.as_ref(), new.as_ref());
481 let (old_node, old_container) =
483 self.namei_exist(None, &old, Self::MAX_SYMLINK_DEREF, false)?;
484
485 let (_new_node, new_container) = self.namei(None, &new, Self::MAX_SYMLINK_DEREF, false)?;
486 let new_name = new
487 .as_ref()
488 .file_name()
489 .ok_or(ArgumentError::InvalidArgument)?
490 .to_str()
491 .ok_or(ArgumentError::InvalidArgument)?;
492
493 let new_entry = if old_node.kind == NsNodeKind::SymLink {
495 NsNode::new(
496 NsNodeKind::SymLink,
497 old_node.id,
498 &new_name,
499 Some(old_node.readlink()?),
500 )?
501 } else {
502 NsNode::new::<_, &str>(old_node.kind, old_node.id, &new_name, None)?
503 };
504
505 tracing::trace!(
506 "insert new entry: {:?} in container {}",
507 new_entry,
508 new_container.id()
509 );
510 let _ = new_container.remove(new_name);
512 new_container.insert(new_entry);
513 old_container
514 .remove(old_node.name()?)
515 .map(|_| ())
516 .ok_or(NamingError::NotFound.into())
517 }
518
519 pub fn link<P: AsRef<Path>, L: AsRef<Path>>(&self, name: P, link: L) -> Result<()> {
520 let (node, container) = self.namei(None, &name, Self::MAX_SYMLINK_DEREF, false)?;
521 let Err(name) = node else {
522 return Err(NamingError::AlreadyExists.into());
523 };
524
525 container.insert(NsNode::symlink(name, link)?);
526 Ok(())
527 }
528
529 pub fn readlink<P: AsRef<Path>>(&self, name: P) -> Result<PathBuf> {
530 let (node, _) = self.namei_exist(None, name, Self::MAX_SYMLINK_DEREF, false)?;
531 node.readlink().map(PathBuf::from)
532 }
533}
534
535bitflags! {
536 #[derive(Clone, Copy, Default, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
537 pub struct GetFlags: u32 {
538 const FOLLOW_SYMLINK = 1;
539 }
540}