Skip to content

Commit 481efa0

Browse files
committed
Merge branch 'main' into node-gats
2 parents 3c7b454 + 3d46c94 commit 481efa0

10 files changed

Lines changed: 253 additions & 60 deletions

File tree

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ jobs:
147147
toolchain: stable
148148

149149
- name: Run cargo-machete
150-
uses: bnjbvr/cargo-machete@v0.9.1
150+
uses: bnjbvr/cargo-machete@v0.9.2
151151

152152
minimal-versions:
153153
if: github.event_name == 'push' || github.event_name == 'schedule' || github.event.pull_request.head.repo.full_name != github.repository

src/error.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
//! Error types for the `dtoolkit` crate.
1010
11+
#[cfg(feature = "write")]
12+
use alloc::string::String;
13+
1114
use thiserror::Error;
1215

1316
/// An error that can occur when accessing a standard node or property.
@@ -78,6 +81,12 @@ pub enum FdtErrorKind {
7881
/// An invalid string was encountered.
7982
#[error("Invalid string in FDT")]
8083
InvalidString,
84+
/// A node name is invalid.
85+
#[error("Invalid node name")]
86+
InvalidNodeName,
87+
/// A property name is invalid.
88+
#[error("Invalid property name")]
89+
InvalidPropertyName,
8190
/// Memory reservation block has not been terminated with a null entry.
8291
#[error("Memory reservation block was not terminated with a null entry")]
8392
MemReserveNotTerminated,
@@ -109,3 +118,16 @@ pub enum PropertyError {
109118
chunk: usize,
110119
},
111120
}
121+
122+
/// An error that can occur when building or modifying a device tree model.
123+
#[derive(Debug, Clone, PartialEq, Eq, Error)]
124+
#[non_exhaustive]
125+
#[cfg(feature = "write")]
126+
pub enum ModelError {
127+
/// The node name is invalid.
128+
#[error("Invalid node name: '{0}'")]
129+
InvalidNodeName(String),
130+
/// The property name is invalid.
131+
#[error("Invalid property name: '{0}'")]
132+
InvalidPropertyName(String),
133+
}

src/fdt.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,9 +345,22 @@ impl<'a> Fdt<'a> {
345345
FdtToken::BeginNode => {
346346
depth += 1;
347347
offset += FDT_TAGSIZE;
348+
let end_offset = self.find_string_end(offset)?;
348349
// Validate name
349-
offset = self.find_string_end(offset)?;
350-
offset = Self::align_tag_offset(offset);
350+
if check_strings {
351+
let name = self.string_at_offset(offset, Some(end_offset))?;
352+
if depth == 1 {
353+
if !name.is_empty() {
354+
return Err(FdtParseError::new(
355+
FdtErrorKind::InvalidNodeName,
356+
offset,
357+
));
358+
}
359+
} else if name.is_empty() || !crate::validate::is_valid_node_name(name) {
360+
return Err(FdtParseError::new(FdtErrorKind::InvalidNodeName, offset));
361+
}
362+
}
363+
offset = Self::align_tag_offset(end_offset);
351364
}
352365
FdtToken::EndNode => {
353366
if depth == 0 {
@@ -640,7 +653,13 @@ impl<'a> Fdt<'a> {
640653
as usize;
641654

642655
if check_name {
643-
self.string(nameoff)?;
656+
let name = self.string(nameoff)?;
657+
if !crate::validate::is_valid_property_name(name) {
658+
return Err(FdtParseError::new(
659+
FdtErrorKind::InvalidPropertyName,
660+
offset + FDT_TAGSIZE,
661+
));
662+
}
644663
}
645664

646665
let prop_offset = offset + 2 * FDT_TAGSIZE;

src/fdt/property.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use crate::Property;
2020
pub struct FdtProperty<'a> {
2121
name: &'a str,
2222
value: &'a [u8],
23-
value_offset: usize,
2423
}
2524

2625
impl<'a> Property for FdtProperty<'a> {
@@ -148,11 +147,7 @@ impl<'a> FdtPropIter<'a> {
148147
.data
149148
.get(prop_offset..prop_offset + len)
150149
.expect("Fdt should be valid");
151-
return Some(FdtProperty {
152-
name,
153-
value,
154-
value_offset: prop_offset,
155-
});
150+
return Some(FdtProperty { name, value });
156151
}
157152
FdtToken::Nop => *offset += FDT_TAGSIZE,
158153
_ => return None,

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
//!
5555
//! // Add a child node to the root.
5656
//! let child = DeviceTreeNode::builder("child")
57-
//! .property(DeviceTreeProperty::new("my-property", "hello\0"))
57+
//! .unwrap()
58+
//! .property(DeviceTreeProperty::new("my-property", "hello\0").unwrap())
5859
//! .build();
5960
//! tree.root.add_child(child);
6061
//!
@@ -90,6 +91,7 @@ pub mod model;
9091
pub mod standard;
9192
mod util;
9293
mod values;
94+
mod validate;
9395

9496
use core::fmt::{self, Display, Formatter};
9597
use core::ops::{BitOr, Shl};

src/model.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use crate::memreserve::MemoryReservation;
3636
/// ```
3737
/// # use dtoolkit::model::{DeviceTree, DeviceTreeNode};
3838
/// let mut tree = DeviceTree::new();
39-
/// tree.root.add_child(DeviceTreeNode::new("child"));
39+
/// tree.root.add_child(DeviceTreeNode::new("child").unwrap());
4040
/// let child = tree.find_node_mut("/child").unwrap();
4141
/// ```
4242
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -60,7 +60,7 @@ impl DeviceTree {
6060
#[must_use]
6161
pub fn new() -> Self {
6262
Self {
63-
root: DeviceTreeNode::new("/"),
63+
root: DeviceTreeNode::new_unchecked(""),
6464
memory_reservations: Vec::new(),
6565
}
6666
}
@@ -104,7 +104,7 @@ impl DeviceTree {
104104
/// use dtoolkit::model::{DeviceTree, DeviceTreeNode};
105105
///
106106
/// let mut tree = DeviceTree::new();
107-
/// tree.root.add_child(DeviceTreeNode::new("child"));
107+
/// tree.root.add_child(DeviceTreeNode::new("child").unwrap());
108108
/// let child = tree.find_node_mut("/child").unwrap();
109109
/// assert_eq!((&*child).name(), "child");
110110
/// ```

src/model/node.rs

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use indexmap::IndexMap;
1313
use twox_hash::xxhash64;
1414

1515
use super::property::DeviceTreeProperty;
16+
use crate::error::ModelError;
1617
use crate::{Node, Property};
1718

1819
/// A mutable, in-memory representation of a device tree node.
@@ -85,9 +86,9 @@ impl Node for DeviceTreeNode {
8586
/// use dtoolkit::Node;
8687
/// use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
8788
///
88-
/// let mut node = DeviceTreeNode::new("my-node");
89-
/// node.add_child(DeviceTreeNode::new("child"));
90-
/// let child = (&node).child("child");
89+
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
90+
/// node.add_child(DeviceTreeNode::new("child").unwrap());
91+
/// let child = node.child("child");
9192
/// assert!(child.is_some());
9293
/// ```
9394
fn child(&self, name: &str) -> Option<&Self> {
@@ -148,8 +149,8 @@ impl<'a> Node for &'a DeviceTreeNode {
148149
/// use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
149150
/// use dtoolkit::{Node, Property};
150151
///
151-
/// let mut node = DeviceTreeNode::new("my-node");
152-
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]));
152+
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
153+
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
153154
/// let prop = (&node).property("my-prop").unwrap();
154155
/// assert_eq!(prop.value(), &[1, 2, 3, 4]);
155156
/// ```
@@ -176,8 +177,8 @@ impl<'a> Node for &'a DeviceTreeNode {
176177
/// use dtoolkit::Node;
177178
/// use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
178179
///
179-
/// let mut node = DeviceTreeNode::new("my-node");
180-
/// node.add_child(DeviceTreeNode::new("child"));
180+
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
181+
/// node.add_child(DeviceTreeNode::new("child").unwrap());
181182
/// let child = (&node).child("child");
182183
/// assert!(child.is_some());
183184
/// ```
@@ -229,26 +230,42 @@ mod private {
229230
impl DeviceTreeNode {
230231
/// Creates a new [`DeviceTreeNode`] with the given name.
231232
///
233+
/// # Errors
234+
///
235+
/// Returns a [`ModelError::InvalidNodeName`] if the node name is invalid.
236+
///
232237
/// # Examples
233238
///
234239
/// ```
235240
/// use dtoolkit::Node;
236241
/// use dtoolkit::model::DeviceTreeNode;
237242
///
238-
/// let node = DeviceTreeNode::new("my-node");
243+
/// let node = DeviceTreeNode::new("my-node").unwrap();
239244
/// assert_eq!(node.name(), "my-node");
240245
/// ```
246+
pub fn new(name: impl Into<String>) -> Result<Self, ModelError> {
247+
let name = name.into();
248+
if !crate::validate::is_valid_node_name(&name) {
249+
return Err(ModelError::InvalidNodeName(name));
250+
}
251+
Ok(Self::new_unchecked(name))
252+
}
253+
254+
/// Creates a new [`DeviceTreeNode`] with the given name without validation.
241255
#[must_use]
242-
pub fn new(name: impl Into<String>) -> Self {
256+
pub fn new_unchecked(name: impl Into<String>) -> Self {
243257
Self {
244258
name: name.into(),
245259
..Default::default()
246260
}
247261
}
248262

249263
/// Creates a new [`DeviceTreeNodeBuilder`] with the given name.
250-
#[must_use]
251-
pub fn builder(name: impl Into<String>) -> DeviceTreeNodeBuilder {
264+
///
265+
/// # Errors
266+
///
267+
/// Returns a [`ModelError::InvalidNodeName`] if the node name is invalid.
268+
pub fn builder(name: impl Into<String>) -> Result<DeviceTreeNodeBuilder, ModelError> {
252269
DeviceTreeNodeBuilder::new(name)
253270
}
254271

@@ -269,8 +286,8 @@ impl DeviceTreeNode {
269286
/// use dtoolkit::Property;
270287
/// use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
271288
///
272-
/// let mut node = DeviceTreeNode::new("my-node");
273-
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]));
289+
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
290+
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
274291
/// let prop = node.property_mut("my-prop").unwrap();
275292
/// prop.set_value(vec![5, 6, 7, 8]);
276293
/// assert_eq!((&*prop).value(), &[5, 6, 7, 8]);
@@ -292,9 +309,9 @@ impl DeviceTreeNode {
292309
/// use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
293310
/// use dtoolkit::{Node, Property};
294311
///
295-
/// let mut node = DeviceTreeNode::new("my-node");
296-
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]));
297-
/// assert_eq!(node.property("my-prop").unwrap().value(), &[1, 2, 3, 4]);
312+
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
313+
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
314+
/// assert_eq!((&node).property("my-prop").unwrap().value(), &[1, 2, 3, 4]);
298315
/// ```
299316
pub fn add_property(&mut self, property: DeviceTreeProperty) {
300317
self.properties
@@ -314,8 +331,8 @@ impl DeviceTreeNode {
314331
/// use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
315332
/// use dtoolkit::{Node, Property};
316333
///
317-
/// let mut node = DeviceTreeNode::new("my-node");
318-
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]));
334+
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
335+
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
319336
/// let prop = node.remove_property("my-prop").unwrap();
320337
/// assert_eq!((&prop).value(), &[1, 2, 3, 4]);
321338
/// assert!(node.property("my-prop").is_none());
@@ -341,11 +358,14 @@ impl DeviceTreeNode {
341358
/// use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
342359
/// use dtoolkit::{Node, Property};
343360
///
344-
/// let mut node = DeviceTreeNode::new("my-node");
345-
/// node.add_child(DeviceTreeNode::new("child"));
361+
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
362+
/// node.add_child(DeviceTreeNode::new("child").unwrap());
346363
/// let child = node.child_mut("child").unwrap();
347-
/// child.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]));
348-
/// assert_eq!(child.property("my-prop").unwrap().value(), &[1, 2, 3, 4]);
364+
/// child.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
365+
/// assert_eq!(
366+
/// (&*child).property("my-prop").unwrap().value(),
367+
/// &[1, 2, 3, 4]
368+
/// );
349369
/// ```
350370
#[must_use]
351371
pub fn child_mut(&mut self, name: &str) -> Option<&mut DeviceTreeNode> {
@@ -364,9 +384,9 @@ impl DeviceTreeNode {
364384
/// use dtoolkit::Node;
365385
/// use dtoolkit::model::DeviceTreeNode;
366386
///
367-
/// let mut node = DeviceTreeNode::new("my-node");
368-
/// node.add_child(DeviceTreeNode::new("child"));
369-
/// assert_eq!(node.child("child").unwrap().name(), "child");
387+
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
388+
/// node.add_child(DeviceTreeNode::new("child").unwrap());
389+
/// assert_eq!((&node).child("child").unwrap().name(), "child");
370390
/// ```
371391
pub fn add_child(&mut self, child: DeviceTreeNode) {
372392
self.children.insert(child.name.clone(), child);
@@ -385,8 +405,8 @@ impl DeviceTreeNode {
385405
/// use dtoolkit::Node;
386406
/// use dtoolkit::model::DeviceTreeNode;
387407
///
388-
/// let mut node = DeviceTreeNode::new("my-node");
389-
/// node.add_child(DeviceTreeNode::new("child"));
408+
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
409+
/// node.add_child(DeviceTreeNode::new("child").unwrap());
390410
/// let child = node.remove_child("child").unwrap();
391411
/// assert_eq!(child.name(), "child");
392412
/// assert!(node.child("child").is_none());
@@ -427,10 +447,10 @@ pub struct DeviceTreeNodeBuilder {
427447
}
428448

429449
impl DeviceTreeNodeBuilder {
430-
fn new(name: impl Into<String>) -> Self {
431-
Self {
432-
node: DeviceTreeNode::new(name),
433-
}
450+
fn new(name: impl Into<String>) -> Result<Self, ModelError> {
451+
Ok(Self {
452+
node: DeviceTreeNode::new(name)?,
453+
})
434454
}
435455

436456
/// Adds a property to the node.

src/model/property.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use core::str;
1212

1313
use zerocopy::FromBytes;
1414

15+
use crate::error::ModelError;
1516
use crate::values::{FdtStringListIterator, PropEncodedArrayIterator};
1617
use crate::{Cells, Property};
1718

@@ -42,18 +43,36 @@ impl<'a> Property for &'a DeviceTreeProperty {
4243
impl DeviceTreeProperty {
4344
/// Creates a new `DeviceTreeProperty` with the given name and value.
4445
///
46+
/// # Errors
47+
///
48+
/// Returns a [`ModelError::InvalidPropertyName`] if the property name is
49+
/// invalid.
50+
///
4551
/// # Examples
4652
///
4753
/// ```
4854
/// use dtoolkit::Property;
4955
/// use dtoolkit::model::DeviceTreeProperty;
5056
///
51-
/// let prop = DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]);
57+
/// let prop = DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap();
5258
/// assert_eq!((&prop).name(), "my-prop");
5359
/// assert_eq!((&prop).value(), &[1, 2, 3, 4]);
5460
/// ```
61+
pub fn new(name: impl Into<String>, value: impl Into<Vec<u8>>) -> Result<Self, ModelError> {
62+
let name = name.into();
63+
if !crate::validate::is_valid_property_name(&name) {
64+
return Err(ModelError::InvalidPropertyName(name));
65+
}
66+
Ok(Self {
67+
name,
68+
value: value.into(),
69+
})
70+
}
71+
72+
/// Creates a new `DeviceTreeProperty` with the given name and value without
73+
/// validation.
5574
#[must_use]
56-
pub fn new(name: impl Into<String>, value: impl Into<Vec<u8>>) -> Self {
75+
pub fn new_unchecked(name: impl Into<String>, value: impl Into<Vec<u8>>) -> Self {
5776
Self {
5877
name: name.into(),
5978
value: value.into(),
@@ -68,7 +87,7 @@ impl DeviceTreeProperty {
6887
/// use dtoolkit::Property;
6988
/// use dtoolkit::model::DeviceTreeProperty;
7089
///
71-
/// let mut prop = DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]);
90+
/// let mut prop = DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap();
7291
/// prop.set_value(vec![5, 6, 7, 8]);
7392
/// assert_eq!((&prop).value(), &[5, 6, 7, 8]);
7493
/// ```

0 commit comments

Comments
 (0)