fuchsia_archive/
name.rs
1use crate::Error;
6
7enum CurrentSegment {
8 Empty,
9 Dot,
10 DotDot,
11 Other,
12}
13use CurrentSegment::*;
14
15pub fn validate_name(name: &[u8]) -> Result<&[u8], Error> {
18 let mut state = Empty;
19 for c in name.iter() {
20 state = match c {
21 b'\0' => return Err(Error::NameContainsNull(name.into())),
22 b'/' => match state {
23 Empty => {
24 if name[0] == b'/' {
25 return Err(Error::NameStartsWithSlash(name.into()));
26 }
27 return Err(Error::NameContainsEmptySegment(name.into()));
28 }
29 Dot => return Err(Error::NameContainsDotSegment(name.into())),
30 DotDot => return Err(Error::NameContainsDotDotSegment(name.into())),
31 Other => Empty,
32 },
33 b'.' => match state {
34 Empty => Dot,
35 Dot => DotDot,
36 DotDot | Other => Other,
37 },
38 _ => Other,
39 }
40 }
41
42 match state {
43 Empty => {
44 if name.is_empty() {
45 Err(Error::ZeroLengthName)
46 } else {
47 Err(Error::NameEndsWithSlash(name.into()))
48 }
49 }
50 Dot => Err(Error::NameContainsDotSegment(name.into())),
51 DotDot => Err(Error::NameContainsDotDotSegment(name.into())),
52 Other => Ok(name),
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59 use assert_matches::assert_matches;
60
61 #[test]
62 fn valid_names() {
63 for name in
64 ["a", "a/a", "a/a/a", ".a", "a.", "..a", "a..", "a./a", "a../a", "a/.a", "a/..a"].iter()
65 {
66 assert_matches!(validate_name(name.as_bytes()), Ok(n) if n == name.as_bytes());
67 }
68 }
69
70 #[test]
71 fn invalid_names() {
72 assert_matches!(validate_name(b""), Err(Error::ZeroLengthName));
73
74 for name in ["/", "/a"].iter() {
75 assert_matches!(
76 validate_name(name.as_bytes()),
77 Err(Error::NameStartsWithSlash(n)) if n == name.as_bytes()
78 );
79 }
80
81 for name in ["a/", "aa/"].iter() {
82 assert_matches!(
83 validate_name(name.as_bytes()),
84 Err(Error::NameEndsWithSlash(n)) if n == name.as_bytes()
85 );
86 }
87
88 for name in ["\0", "a\0", "\0a", "a/\0", "\0/a"].iter() {
89 assert_matches!(
90 validate_name(name.as_bytes()),
91 Err(Error::NameContainsNull(n)) if n == name.as_bytes()
92 );
93 }
94
95 for name in ["a//a", "a/a//a"].iter() {
96 assert_matches!(
97 validate_name(name.as_bytes()),
98 Err(Error::NameContainsEmptySegment(n)) if n == name.as_bytes()
99 );
100 }
101
102 for name in [".", "./a", "a/.", "a/./a"].iter() {
103 assert_matches!(
104 validate_name(name.as_bytes()),
105 Err(Error::NameContainsDotSegment(n)) if n == name.as_bytes()
106 );
107 }
108
109 for name in ["..", "../a", "a/..", "a/../a"].iter() {
110 assert_matches!(
111 validate_name(name.as_bytes()),
112 Err(Error::NameContainsDotDotSegment(n)) if n == name.as_bytes()
113 );
114 }
115 }
116}