diff --git a/crates/shim/Cargo.toml b/crates/shim/Cargo.toml index 55e55f27..bcc1d1b7 100644 --- a/crates/shim/Cargo.toml +++ b/crates/shim/Cargo.toml @@ -36,7 +36,6 @@ signal-hook = "0.3.13" oci-spec = "0.6.0" prctl = "1.0.0" page_size = "0.6.0" -regex = "1" containerd-shim-protos = { path = "../shim-protos", version = "0.5.0" } diff --git a/crates/shim/src/mount.rs b/crates/shim/src/mount.rs index f823a50a..9c93c8c6 100644 --- a/crates/shim/src/mount.rs +++ b/crates/shim/src/mount.rs @@ -29,7 +29,6 @@ use log::error; use nix::mount::{mount, MsFlags}; #[cfg(target_os = "linux")] use nix::unistd::{fork, ForkResult}; -use regex::Regex; use crate::error::{Error, Result}; #[cfg(not(feature = "async"))] @@ -239,49 +238,40 @@ fn options_size(options: &[String]) -> usize { options.iter().fold(0, |sum, x| sum + x.len()) } -fn longest_common_prefix(dirs: &[String]) -> Option { +fn longest_common_prefix(dirs: &[String]) -> &str { if dirs.is_empty() { - return None; - } - if dirs.len() == 1 { - if dirs[0].is_empty() { - return None; - } - return Some(dirs[0].to_string()); + return ""; } - let min = dirs.iter().min().unwrap(); - let max = dirs.iter().max().unwrap(); - let min_chars = min.chars().collect::>(); - let max_chars = max.chars().collect::>(); - let mut i = 0; - while i < min_chars.len() && i < max_chars.len() { - if min_chars[i] != max_chars[i] { - if i == 0 { - return None; + let first_dir = &dirs[0]; + + for (i, byte) in first_dir.as_bytes().iter().enumerate() { + for dir in dirs { + if dir.as_bytes().get(i) != Some(byte) { + let mut end = i; + // guaranteed not to underflow since is_char_boundary(0) is always true + while !first_dir.is_char_boundary(end) { + end -= 1; + } + + return &first_dir[0..end]; } - return Some(min[0..i].to_string()); } - i += 1; } - if min.is_empty() { - None - } else { - Some(min.to_string()) - } + first_dir } // NOTE: the snapshot id is based on digits. -// in order to avoid to get snapshots/x, shoule be back to parent dir. +// in order to avoid to get snapshots/x, should be back to parent dir. // however, there is assumption that the common dir is ${root}/io.containerd.v1.overlayfs/snapshots. #[cfg(target_os = "linux")] fn trim_flawed_dir(s: &str) -> String { - let r = Regex::new(r"((/[^/]+)+/)([^/]*)").unwrap(); - r.replace(s, "$1").to_string() + s[0..s.rfind('/').unwrap_or(0) + 1].to_owned() } #[cfg(target_os = "linux")] +#[derive(Default)] struct LowerdirCompactor { options: Vec, lowerdirs: Option>, @@ -293,8 +283,7 @@ impl LowerdirCompactor { fn new(options: &[String]) -> Self { Self { options: options.to_vec(), - lowerdirs: None, - lowerdir_prefix: None, + ..Self::default() } } @@ -317,9 +306,7 @@ impl LowerdirCompactor { .as_ref() .filter(|x| x.len() > 1) .map(|x| longest_common_prefix(x)) - .unwrap_or(None) - .filter(|x| x != "/") - .map(|x| trim_flawed_dir(&x)) + .map(trim_flawed_dir) .filter(|x| !x.is_empty() && x != "/"); self } @@ -620,6 +607,8 @@ mod tests { #[test] fn test_trim_flawed_dir() { let mut tcases: Vec<(&str, String)> = Vec::new(); + tcases.push(("/", "/".to_string())); + tcases.push(("/foo", "/".to_string())); tcases.push(("/.foo-_bar/foo", "/.foo-_bar/".to_string())); tcases.push(("/.foo-_bar/foo/", "/.foo-_bar/foo/".to_string())); tcases.push(("/.foo-_bar/foo/bar", "/.foo-_bar/foo/".to_string())); @@ -632,21 +621,21 @@ mod tests { #[test] fn test_longest_common_prefix() { - let mut tcases: Vec<(Vec, Option)> = Vec::new(); - tcases.push((vec![], None)); - tcases.push((vec!["foo".to_string()], Some("foo".to_string()))); - tcases.push((vec!["foo".to_string(), "bar".to_string()], None)); + let mut tcases: Vec<(Vec, String)> = Vec::new(); + tcases.push((vec![], "".to_string())); + tcases.push((vec!["foo".to_string()], "foo".to_string())); + tcases.push((vec!["foo".to_string(), "bar".to_string()], "".to_string())); tcases.push(( vec!["foo".to_string(), "foo".to_string()], - Some("foo".to_string()), + "foo".to_string(), )); tcases.push(( vec!["foo".to_string(), "foobar".to_string()], - Some("foo".to_string()), + "foo".to_string(), )); tcases.push(( vec!["foo".to_string(), "".to_string(), "foobar".to_string()], - None, + "".to_string(), )); for (case, expected) in tcases { let res = longest_common_prefix(&case);