naming_core/
store.rs

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    // Loads in an existing object store from an Object ID
166    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    // Loads in an existing object store from an Object ID
180    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    // session is created from root
193    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    // This function will return a reference to an entry described by name: P relative to working_ns
238    // If the name is absolute then it will start at root instead of the working_ns
239    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                    // Did we find something?
298                    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                        // Last component: return with this name, None.
305                        if is_last {
306                            return Ok((Err(os_str.into()), namespace));
307                        } else {
308                            return Err(NamingError::NotFound.into());
309                        }
310                    };
311                    // If symlink, deref. But keep track of recursion.
312                    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            // Unwrap-Ok: we checked if it's empty earlier.
363            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        // Look up the old entry (don't follow symlinks — we're moving the entry itself)
482        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        // Create new entry preserving the old node's type and data
494        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        // Insert at new location, then remove from old location
511        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}