grit_lib/transport_path.rs
1//! Safety checks for local transport URLs (matches Git `connect.c` / `path.c`).
2
3use thiserror::Error;
4
5/// Errors returned while validating local transport paths.
6#[derive(Clone, Debug, Error, PartialEq, Eq)]
7pub enum TransportPathError {
8 /// A repository path begins with `-` and could be interpreted as a command option.
9 #[error("fatal: strange pathname '{0}' blocked")]
10 OptionLikePath(String),
11}
12
13/// Returns true when `s` is non-empty and begins with `-`, matching Git's
14/// `looks_like_command_line_option` (used before quoting a path for shell-backed transport).
15#[must_use]
16pub fn looks_like_command_line_option(s: &str) -> bool {
17 !s.is_empty() && s.starts_with('-')
18}
19
20/// Rejects repository path strings that could be mistaken for options when passed to a shell.
21///
22/// Git dies with `strange pathname '%s' blocked` when the parsed local path starts with `-`.
23/// Absolute paths like `/tmp/-repo.git` are allowed because the path string begins with `/`.
24pub fn check_local_url_path_not_option_like(url: &str) -> Result<(), TransportPathError> {
25 let path = url
26 .strip_prefix("file://")
27 .unwrap_or(url)
28 .split('?')
29 .next()
30 .unwrap_or("");
31 if looks_like_command_line_option(path) {
32 return Err(TransportPathError::OptionLikePath(path.to_owned()));
33 }
34 Ok(())
35}