libfdt: Add adb_subnode_with_name_len() and subnode_with_name_len()
APIs are added to create a node and its supernodes without allocating
tokenized names.
Bug: 277993056
Test: atest liblibfdt.integration_test
Change-Id: I5a43d41e0bea1e9b7d0182b98d9aa5e0c079dd2e
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 5683ce3..d800c13 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -670,12 +670,49 @@
/// Adds a new subnode to the given node and return it as a FdtNodeMut on success.
pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
+ let offset = self.add_subnode_offset(name.to_bytes())?;
+ Ok(Self { fdt: self.fdt, offset })
+ }
+
+ /// Adds a new subnode to the given node with name and namelen, and returns it as a FdtNodeMut
+ /// on success.
+ pub fn add_subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Self> {
+ let offset = { self.add_subnode_offset(&name.to_bytes()[..namelen])? };
+ Ok(Self { fdt: self.fdt, offset })
+ }
+
+ fn add_subnode_offset(&mut self, name: &[u8]) -> Result<c_int> {
+ let namelen = name.len().try_into().unwrap();
// SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
let ret = unsafe {
- libfdt_bindgen::fdt_add_subnode(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
+ libfdt_bindgen::fdt_add_subnode_namelen(
+ self.fdt.as_mut_ptr(),
+ self.offset,
+ name.as_ptr().cast::<_>(),
+ namelen,
+ )
};
+ fdt_err(ret)
+ }
- Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
+ /// Returns the subnode of the given name with len.
+ pub fn subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Option<Self>> {
+ let offset = self.subnode_offset(&name.to_bytes()[..namelen])?;
+ Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
+ }
+
+ fn subnode_offset(&self, name: &[u8]) -> Result<Option<c_int>> {
+ let namelen = name.len().try_into().unwrap();
+ // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
+ let ret = unsafe {
+ libfdt_bindgen::fdt_subnode_offset_namelen(
+ self.fdt.as_ptr(),
+ self.offset,
+ name.as_ptr().cast::<_>(),
+ namelen,
+ )
+ };
+ fdt_err_or_option(ret)
}
fn parent(&'a self) -> Result<FdtNode<'a>> {
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index 65ebc4d..61503eb 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -17,7 +17,7 @@
//! Integration tests of the library libfdt.
use libfdt::{Fdt, FdtError, Phandle};
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
use std::fs;
use std::ops::Range;
@@ -189,3 +189,34 @@
assert!(fdt.node_with_phandle(Phandle::new(0xFF).unwrap()).unwrap().is_none());
assert!(fdt.node(cstr!("/node_z/node_zz")).unwrap().is_none());
}
+
+#[test]
+fn node_add_subnode_with_namelen() {
+ let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
+ data.resize(data.len() * 2, 0_u8);
+
+ let fdt = Fdt::from_mut_slice(&mut data).unwrap();
+ fdt.unpack().unwrap();
+
+ let node_path = cstr!("/node_z/node_zz");
+ let subnode_name = cstr!("123456789");
+
+ for len in 0..subnode_name.to_bytes().len() {
+ let mut node = fdt.node_mut(node_path).unwrap().unwrap();
+ assert!(node.subnode_with_namelen(subnode_name, len).unwrap().is_none());
+
+ let mut node = fdt.node_mut(node_path).unwrap().unwrap();
+ node.add_subnode_with_namelen(subnode_name, len).unwrap();
+
+ let mut node = fdt.node_mut(node_path).unwrap().unwrap();
+ assert!(node.subnode_with_namelen(subnode_name, len).unwrap().is_some());
+ }
+
+ let node_path = node_path.to_str().unwrap();
+ for len in 1..subnode_name.to_bytes().len() {
+ let name = String::from_utf8(subnode_name.to_bytes()[..len].to_vec()).unwrap();
+ let path = CString::new(format!("{node_path}/{name}")).unwrap();
+ let subnode = fdt.node(&path).unwrap().unwrap();
+ assert_eq!(subnode.name().unwrap().to_str().unwrap(), name);
+ }
+}