///|
fn comparable(path : String) -> String {
if @platform.is_windows() {
path.to_lower()
} else {
path
}
}
///|
fn canonical_path(path : String) -> String {
let separator = @path.sep.to_string()
let mut normalized = @path.Path(@platform.normalize_input_separators(path))
.normalize()
.to_string()
while normalized.has_suffix(separator) {
let parent = @path.Path(normalized).dirname().to_string()
if comparable(parent) == comparable(normalized) {
break
}
normalized = normalized[:normalized.length() - separator.length()].to_owned()
}
normalized
}
///|
fn is_filesystem_root(path : String) -> Bool {
let normalized = canonical_path(path)
let value = @path.Path(normalized)
value.is_absolute() &&
comparable(canonical_path(value.dirname().to_string())) ==
comparable(normalized)
}
///|
fn is_same_or_descendant(path : String, root : String) -> Bool {
let normalized_path = canonical_path(path)
let normalized_root = canonical_path(root)
if comparable(normalized_path) == comparable(normalized_root) {
return true
}
let prefix = if normalized_root.has_suffix(@path.sep.to_string()) {
normalized_root
} else {
normalized_root + @path.sep.to_string()
}
comparable(normalized_path).has_prefix(comparable(prefix))
}
///|
fn protects_working_directory(path : String) -> Bool {
if is_filesystem_root(path) {
return true
}
guard @env.current_dir() is Some(current) else {
let normalized = canonical_path(path)
return normalized == "." ||
normalized == ".." ||
normalized.has_prefix("../")
}
let current = canonical_path(current)
let target = @path.Path(path)
let target = if target.is_absolute() {
canonical_path(target.to_string())
} else {
canonical_path(@path.Path(current).join(target).to_string())
}
comparable(target) == comparable(current) ||
is_same_or_descendant(current, target)
}