From be5bf4f1e2a8a61e6277e0a568cd3d0be058f0ae Mon Sep 17 00:00:00 2001 From: licunlong Date: Mon, 24 Jul 2023 11:47:53 +0800 Subject: [PATCH] fix: add two helper function to check if the path name is safe, and path length is valid --- libs/basic/src/path_util.rs | 98 +++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/libs/basic/src/path_util.rs b/libs/basic/src/path_util.rs index 7391615..58f8e49 100644 --- a/libs/basic/src/path_util.rs +++ b/libs/basic/src/path_util.rs @@ -14,6 +14,12 @@ //! use std::path::Path; +/// The maximum length of a linux path +pub const PATH_LENGTH_MAX: usize = 4096; + +/// The maximum length of a linux file name +pub const FILE_LENGTH_MAX: usize = 255; + /// return true if the path of a and b equaled. pub fn path_equal(a: &str, b: &str) -> bool { let p_a = Path::new(a); @@ -21,6 +27,58 @@ pub fn path_equal(a: &str, b: &str) -> bool { p_a == p_b } +/// check if the path name contains unsafe character +/// +/// return true if it doesn't contain unsafe character +pub fn path_name_is_safe(s: &str) -> bool { + if s.is_empty() { + return false; + } + for c in s.chars() { + if c > 0 as char && c < ' ' { + return false; + } + if (c as char).is_ascii_control() { + return false; + } + } + true +} + +/// check if the path length is valid +pub fn path_length_is_valid(s: &str) -> bool { + if s.is_empty() { + return false; + } + if s.len() > PATH_LENGTH_MAX { + return false; + } + let mut de_len = 0; + let mut last_c = '/'; + for c in s.chars() { + match c { + '/' => { + de_len = 0; + } + '.' => { + if last_c == '/' { + de_len = 1; + } else { + de_len += 1; + } + } + _ => { + de_len += 1; + } + } + if de_len > FILE_LENGTH_MAX { + return false; + } + last_c = c; + } + true +} + /// Remove redundant inner and trailing slashes and unnecessary dots to simplify path. /// e.g., //foo//.//bar/ becomes /foo/bar /// .//foo//.//bar/ becomes foo/bar @@ -77,4 +135,44 @@ mod tests { assert_eq!(path_simplify(".//foo//.//bar/"), "foo/bar"); assert_eq!(path_simplify("foo//.//bar/"), "foo/bar"); } + + #[test] + fn test_path_name_is_safe() { + assert!(!path_name_is_safe("")); + assert!(path_name_is_safe("/abc")); + assert!(!path_name_is_safe("/abc\x7f/a")); + assert!(!path_name_is_safe("/abc\x1f/a")); + assert!(!path_name_is_safe("/\x0a/a")); + } + + #[test] + fn test_path_length_is_valid() { + assert!(!path_length_is_valid("")); + + let path = "/a/".to_string() + &String::from_iter(vec!['1'; 255]); + assert!(path_length_is_valid(&path)); + + let path = "/a/".to_string() + &String::from_iter(vec!['1'; 256]); + assert!(!path_length_is_valid(&path)); + + let path = "/a/".to_string() + &String::from_iter(vec!['/'; 256]); + assert!(path_length_is_valid(&path)); + + let path = "/a/".to_string() + &String::from_iter(vec!['.'; 255]); + assert!(path_length_is_valid(&path)); + + let mut path = "".to_string(); + for _ in 0..40 { + path += "/"; + path += &String::from_iter(vec!['1'; 100]); + } + assert!(path_length_is_valid(&path)); + + let mut path = "".to_string(); + for _ in 0..41 { + path += "/"; + path += &String::from_iter(vec!['1'; 100]); + } + assert!(!path_length_is_valid(&path)); + } } -- 2.33.0