Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion crates/shim/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }

Expand Down
69 changes: 29 additions & 40 deletions crates/shim/src/mount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down Expand Up @@ -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<String> {
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::<Vec<char>>();
let max_chars = max.chars().collect::<Vec<char>>();
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<String>,
lowerdirs: Option<Vec<String>>,
Expand All @@ -293,8 +283,7 @@ impl LowerdirCompactor {
fn new(options: &[String]) -> Self {
Self {
options: options.to_vec(),
lowerdirs: None,
lowerdir_prefix: None,
..Self::default()
}
}

Expand All @@ -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
}
Expand Down Expand Up @@ -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()));
Expand All @@ -632,21 +621,21 @@ mod tests {

#[test]
fn test_longest_common_prefix() {
let mut tcases: Vec<(Vec<String>, Option<String>)> = 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>, 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);
Expand Down