Skip to content

Commit 91cae4f

Browse files
committed
add function to read blob from worktree
1 parent 2ca824b commit 91cae4f

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

gix-worktree/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ pub mod fs;
1313
pub mod index;
1414

1515
pub(crate) mod os;
16+
///
17+
pub mod read;

gix-worktree/src/read.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use crate::fs;
2+
use gix_object::Blob;
3+
use gix_path as path;
4+
use std::borrow::Cow;
5+
use std::fs::{read_link, File};
6+
use std::io;
7+
use std::io::Read;
8+
use std::path::Path;
9+
10+
/// Error returned by [`Blob::read`] and related functions
11+
#[derive(Debug, thiserror::Error)]
12+
pub enum Error {
13+
///
14+
#[error("Could not convert symlink path to UTF8")]
15+
IllformedUtf8,
16+
///
17+
#[error("IO error while reading blob")]
18+
Io(#[from] io::Error),
19+
}
20+
21+
// TODO: what to do about precompose unicode and ignore case_here?
22+
23+
/// Create a blob from a file/symlink
24+
pub fn read_blob(path: &Path, capabilities: &fs::Capabilities) -> Result<Blob, Error> {
25+
let mut buf = Vec::new();
26+
let res = read_blob_to_buf(path, &mut buf, capabilities)?;
27+
match res {
28+
Cow::Borrowed(_) => Ok(Blob { data: buf }),
29+
Cow::Owned(data) => Ok(Blob { data }),
30+
}
31+
}
32+
33+
/// Create a blob from a file/symlink
34+
pub fn read_blob_with_meta(path: &Path, is_symlink: bool, capabilities: &fs::Capabilities) -> Result<Blob, Error> {
35+
let mut buf = Vec::new();
36+
let res = read_blob_to_buf_with_meta(path, is_symlink, &mut buf, capabilities)?;
37+
match res {
38+
Cow::Borrowed(_) => Ok(Blob { data: buf }),
39+
Cow::Owned(data) => Ok(Blob { data }),
40+
}
41+
}
42+
43+
// TODO: there is no reason this should be a Cow
44+
// std isn't great about allowing users to avoid allocations but we could
45+
// simply write our own wrapper around libc::readlink which reuses the
46+
// buffer. This would require unsafe code tough (obviously)
47+
48+
/// Create blob data from a file/symlink
49+
pub fn read_blob_to_buf<'a>(
50+
path: &Path,
51+
buf: &'a mut Vec<u8>,
52+
capabilities: &fs::Capabilities,
53+
) -> Result<Cow<'a, [u8]>, Error> {
54+
read_blob_to_buf_with_meta(path, path.symlink_metadata()?.is_symlink(), buf, capabilities)
55+
}
56+
57+
/// Create a blob from a file/symlink
58+
pub fn read_blob_to_buf_with_meta<'a>(
59+
path: &Path,
60+
is_symlink: bool,
61+
buf: &'a mut Vec<u8>,
62+
capabilities: &fs::Capabilities,
63+
) -> Result<Cow<'a, [u8]>, Error> {
64+
// symlinks are only stored as actual symlinks if the FS supports it otherwise they are just
65+
// normal files with their content equal to the linked path (so can be read normally)
66+
//
67+
if is_symlink && capabilities.symlink {
68+
let symlink_path = path::try_into_bstr(read_link(path)?).map_err(|_| Error::IllformedUtf8)?;
69+
match path::to_unix_separators_on_windows(symlink_path) {
70+
Cow::Borrowed(path) => Ok(Cow::Borrowed(path.as_ref())),
71+
Cow::Owned(path) => Ok(Cow::Owned(path.into())),
72+
}
73+
} else {
74+
buf.clear();
75+
File::open(path)?.read_to_end(buf)?;
76+
// TODO apply filters
77+
Ok(buf.as_slice().into())
78+
}
79+
}

0 commit comments

Comments
 (0)