From be5bf4f1e2a8a61e6277e0a568cd3d0be058f0ae Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
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

