libfdt: Add FdtNode::name()
This is the initial step for supporting iteration over FdtNodes.
Bug: 277993056
Test: atest liblibfdt.integration_test
Change-Id: I19ee85b9ee195f27cc776c8277f88797a6eba97e
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index a305e03..43eadae 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -251,6 +251,18 @@
}
}
+ /// Returns the node name.
+ pub fn name(&self) -> Result<&'a CStr> {
+ let mut len: c_int = 0;
+ // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor). On success, the
+ // function returns valid null terminating string and otherwise returned values are dropped.
+ let name = unsafe { libfdt_bindgen::fdt_get_name(self.fdt.as_ptr(), self.offset, &mut len) }
+ as *const c_void;
+ let len = usize::try_from(fdt_err(len)?).unwrap();
+ let name = self.fdt.get_from_ptr(name, len + 1)?;
+ CStr::from_bytes_with_nul(name).map_err(|_| FdtError::Internal)
+ }
+
/// Retrieve the value of a given <string> property.
pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
let value = if let Some(bytes) = self.getprop(name)? {
@@ -293,11 +305,7 @@
/// Retrieve the value of a given property.
pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
if let Some((prop, len)) = Self::getprop_internal(self.fdt, self.offset, name)? {
- let offset = (prop as usize)
- .checked_sub(self.fdt.as_ptr() as usize)
- .ok_or(FdtError::Internal)?;
-
- Ok(Some(self.fdt.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)?))
+ Ok(Some(self.fdt.get_from_ptr(prop, len)?))
} else {
Ok(None) // property was not found
}
@@ -327,7 +335,7 @@
let Some(len) = fdt_err_or_option(len)? else {
return Ok(None); // Property was not found.
};
- let len = usize::try_from(len).map_err(|_| FdtError::Internal)?;
+ let len = usize::try_from(len).unwrap();
if prop.is_null() {
// We expected an error code in len but still received a valid value?!
@@ -806,6 +814,12 @@
fdt_err_expect_zero(ret)
}
+ fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
+ let ptr = ptr as usize;
+ let offset = ptr.checked_sub(self.as_ptr() as usize).ok_or(FdtError::Internal)?;
+ self.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)
+ }
+
/// Return a shared pointer to the device tree.
pub fn as_ptr(&self) -> *const c_void {
self.buffer.as_ptr().cast::<_>()
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index 806e6c0..866a2bb 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -17,6 +17,7 @@
//! Integration tests of the library libfdt.
use libfdt::{Fdt, FdtError};
+use std::ffi::CStr;
use std::fs;
use std::ops::Range;
@@ -70,3 +71,19 @@
assert_eq!(fdt.memory().unwrap_err(), FdtError::NotFound);
assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
}
+
+#[test]
+fn node_name() {
+ let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
+ let fdt = Fdt::from_slice(&data).unwrap();
+
+ let root = fdt.root().unwrap();
+ assert_eq!(root.name().unwrap().to_str().unwrap(), "");
+
+ let chosen = fdt.chosen().unwrap().unwrap();
+ assert_eq!(chosen.name().unwrap().to_str().unwrap(), "chosen");
+
+ let nested_node_path = CStr::from_bytes_with_nul(b"/cpus/PowerPC,970@0\0").unwrap();
+ let nested_node = fdt.node(nested_node_path).unwrap().unwrap();
+ assert_eq!(nested_node.name().unwrap().to_str().unwrap(), "PowerPC,970@0");
+}