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 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    // 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        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                    // Did we find something?
295                    let Some(thisnode) = node else {
296                        tracing::trace!("failed to find component: (is_last = {})", is_last);
297                        // Last component: return with this name, None.
298                        if is_last {
299                            return Ok((Err(os_str.into()), namespace));
300                        } else {
301                            return Err(NamingError::NotFound.into());
302                        }
303                    };
304                    // If symlink, deref. But keep track of recursion.
305                    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            // Unwrap-Ok: we checked if it's empty earlier.
335            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}