Skip to content

Commit 3bb9215

Browse files
committed
Check that paths are not absolute
1 parent e31de68 commit 3bb9215

File tree

3 files changed

+77
-36
lines changed

3 files changed

+77
-36
lines changed

gix-path/src/relative_path.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ impl RelativePath {
3838
#[derive(Debug, thiserror::Error)]
3939
#[allow(missing_docs)]
4040
pub enum Error {
41+
#[error("A RelativePath is not allowed to be absolute")]
42+
IsAbsolute,
4143
#[error(transparent)]
4244
ContainsInvalidComponent(#[from] gix_validate::path::component::Error),
4345
#[error(transparent)]
@@ -51,6 +53,11 @@ impl<'a> TryFrom<&'a str> for &'a RelativePath {
5153
use std::path::Path;
5254

5355
let path: &std::path::Path = Path::new(value);
56+
57+
if path.is_absolute() {
58+
return Err(Error::IsAbsolute);
59+
}
60+
5461
let options: Options = Default::default();
5562

5663
for component in path.components() {
@@ -68,6 +75,11 @@ impl<'a> TryFrom<&'a BStr> for &'a RelativePath {
6875

6976
fn try_from(value: &'a BStr) -> Result<Self, Self::Error> {
7077
let path: &std::path::Path = &try_from_bstr(value)?;
78+
79+
if path.is_absolute() {
80+
return Err(Error::IsAbsolute);
81+
}
82+
7183
let options: Options = Default::default();
7284

7385
for component in path.components() {
@@ -87,6 +99,10 @@ impl<'a, const N: usize> TryFrom<&'a [u8; N]> for &'a RelativePath {
8799
fn try_from(value: &'a [u8; N]) -> Result<Self, Self::Error> {
88100
let path: &std::path::Path = try_from_byte_slice(value)?;
89101

102+
if path.is_absolute() {
103+
return Err(Error::IsAbsolute);
104+
}
105+
90106
let options: Options = Default::default();
91107

92108
for component in path.components() {
@@ -105,6 +121,10 @@ impl<'a> TryFrom<&'a BString> for &'a RelativePath {
105121
fn try_from(value: &'a BString) -> Result<Self, Self::Error> {
106122
let path: &std::path::Path = &try_from_bstr(value.as_bstr())?;
107123

124+
if path.is_absolute() {
125+
return Err(Error::IsAbsolute);
126+
}
127+
108128
let options: Options = Default::default();
109129

110130
for component in path.components() {
@@ -131,3 +151,60 @@ impl AsRef<[u8]> for RelativePath {
131151
self.inner.as_bytes()
132152
}
133153
}
154+
155+
#[cfg(test)]
156+
mod tests {
157+
use super::*;
158+
159+
#[cfg(not(windows))]
160+
#[test]
161+
fn absolute_paths_return_err() {
162+
let path_str: &str = "/refs/heads";
163+
let path_bstr: &BStr = path_str.into();
164+
let path_u8: &[u8; 11] = b"/refs/heads";
165+
let path_bstring: BString = "/refs/heads".into();
166+
167+
assert!(matches!(
168+
TryInto::<&RelativePath>::try_into(path_str),
169+
Err(Error::IsAbsolute)
170+
));
171+
assert!(matches!(
172+
TryInto::<&RelativePath>::try_into(path_bstr),
173+
Err(Error::IsAbsolute)
174+
));
175+
assert!(matches!(
176+
TryInto::<&RelativePath>::try_into(path_u8),
177+
Err(Error::IsAbsolute)
178+
));
179+
assert!(matches!(
180+
TryInto::<&RelativePath>::try_into(&path_bstring),
181+
Err(Error::IsAbsolute)
182+
));
183+
}
184+
185+
#[cfg(windows)]
186+
#[test]
187+
fn absolute_paths_return_err() {
188+
let path_str: &str = r"c:\refs\heads";
189+
let path_bstr: &BStr = path_str.into();
190+
let path_u8: &[u8; 11] = r"c:\refs\heads";
191+
let path_bstring: BString = r"c:\refs\heads".into();
192+
193+
assert!(matches!(
194+
TryInto::<&RelativePath>::try_into(path_str),
195+
Err(Error::IsAbsolute)
196+
));
197+
assert!(matches!(
198+
TryInto::<&RelativePath>::try_into(path_bstr),
199+
Err(Error::IsAbsolute)
200+
));
201+
assert!(matches!(
202+
TryInto::<&RelativePath>::try_into(path_u8),
203+
Err(Error::IsAbsolute)
204+
));
205+
assert!(matches!(
206+
TryInto::<&RelativePath>::try_into(&path_bstring),
207+
Err(Error::IsAbsolute)
208+
));
209+
}
210+
}

gix-ref/src/store/file/overlay_iter.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,6 @@ impl<'a> IterInfo<'a> {
296296

297297
fn from_prefix(base: &'a Path, prefix: &'a RelativePath, precompose_unicode: bool) -> std::io::Result<Self> {
298298
let prefix_path = gix_path::from_bstr(prefix);
299-
if prefix_path.is_absolute() {
300-
return Err(std::io::Error::new(
301-
std::io::ErrorKind::InvalidInput,
302-
"prefix must be a relative path, like 'refs/heads/'",
303-
));
304-
}
305299
let iter_root = base.join(&prefix_path);
306300
if prefix.ends_with(b"/") {
307301
Ok(IterInfo::BaseAndIterRoot {

gix-ref/tests/refs/file/store/iter.rs

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -316,21 +316,6 @@ fn loose_iter_with_broken_refs() -> crate::Result {
316316
Ok(())
317317
}
318318

319-
#[test]
320-
fn loose_iter_with_prefix_wont_allow_absolute_paths() -> crate::Result {
321-
let store = store()?;
322-
#[cfg(not(windows))]
323-
let abs_path = "/hello";
324-
#[cfg(windows)]
325-
let abs_path = r"c:\hello";
326-
327-
match store.loose_iter_prefixed(abs_path.try_into().unwrap()) {
328-
Ok(_) => unreachable!("absolute paths aren't allowed"),
329-
Err(err) => assert_eq!(err.to_string(), "prefix must be a relative path, like 'refs/heads/'"),
330-
}
331-
Ok(())
332-
}
333-
334319
#[test]
335320
fn loose_iter_with_prefix() -> crate::Result {
336321
let prefix_with_slash = b"refs/heads/";
@@ -526,21 +511,6 @@ fn overlay_iter_reproduce_1928() -> crate::Result {
526511
Ok(())
527512
}
528513

529-
#[test]
530-
fn overlay_iter_with_prefix_wont_allow_absolute_paths() -> crate::Result {
531-
let store = store_with_packed_refs()?;
532-
#[cfg(not(windows))]
533-
let abs_path = "/hello";
534-
#[cfg(windows)]
535-
let abs_path = r"c:\hello";
536-
537-
match store.iter()?.prefixed(abs_path.try_into().unwrap()) {
538-
Ok(_) => unreachable!("absolute paths aren't allowed"),
539-
Err(err) => assert_eq!(err.to_string(), "prefix must be a relative path, like 'refs/heads/'"),
540-
}
541-
Ok(())
542-
}
543-
544514
#[test]
545515
fn overlay_prefixed_iter() -> crate::Result {
546516
use gix_ref::Target::*;

0 commit comments

Comments
 (0)