mirror of https://github.com/zkat/cacache-rs.git
feat(links): add support for hard linking from the cache
This commit is contained in:
parent
80e5b4135b
commit
e2695a92b0
|
|
@ -1,5 +1,7 @@
|
||||||
#[cfg(feature = "async-std")]
|
#[cfg(feature = "async-std")]
|
||||||
use async_std::fs as afs;
|
use async_std::fs as afs;
|
||||||
|
#[cfg(feature = "link_to")]
|
||||||
|
use std::path::PathBuf;
|
||||||
#[cfg(all(test, feature = "tokio"))]
|
#[cfg(all(test, feature = "tokio"))]
|
||||||
use tokio::fs as afs;
|
use tokio::fs as afs;
|
||||||
|
|
||||||
|
|
@ -22,7 +24,6 @@ where
|
||||||
|
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,58 @@ pub async fn copy_async<'a>(cache: &'a Path, sri: &'a Integrity, to: &'a Path) -
|
||||||
Ok(size as u64)
|
Ok(size as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hard_link_unchecked(cache: &Path, sri: &Integrity, to: &Path) -> Result<()> {
|
||||||
|
let cpath = path::content_path(cache, sri);
|
||||||
|
std::fs::hard_link(cpath, to).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to link cache contents from {} to {}",
|
||||||
|
path::content_path(cache, sri).display(),
|
||||||
|
to.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hard_link(cache: &Path, sri: &Integrity, to: &Path) -> Result<()> {
|
||||||
|
hard_link_unchecked(cache, sri, to)?;
|
||||||
|
let mut reader = open(cache, sri.clone())?;
|
||||||
|
let mut buf = [0u8; 1024 * 8];
|
||||||
|
loop {
|
||||||
|
let read = reader.read(&mut buf).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to read cache contents while verifying integrity for {}",
|
||||||
|
path::content_path(cache, sri).display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
if read == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader.check()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn hard_link_async(cache: &Path, sri: &Integrity, to: &Path) -> Result<()> {
|
||||||
|
hard_link_unchecked(cache, sri, to)?;
|
||||||
|
let mut reader = open_async(cache, sri.clone()).await?;
|
||||||
|
let mut buf = [0u8; 1024 * 8];
|
||||||
|
loop {
|
||||||
|
let read = AsyncReadExt::read(&mut reader, &mut buf)
|
||||||
|
.await
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to read cache contents while verifying integrity for {}",
|
||||||
|
path::content_path(cache, sri).display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
if read == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader.check()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_content(cache: &Path, sri: &Integrity) -> Option<Integrity> {
|
pub fn has_content(cache: &Path, sri: &Integrity) -> Option<Integrity> {
|
||||||
if path::content_path(cache, sri).exists() {
|
if path::content_path(cache, sri).exists() {
|
||||||
Some(sri.clone())
|
Some(sri.clone())
|
||||||
|
|
|
||||||
66
src/get.rs
66
src/get.rs
|
|
@ -300,6 +300,23 @@ where
|
||||||
read::copy_unchecked_async(cache.as_ref(), sri, to.as_ref()).await
|
read::copy_unchecked_async(cache.as_ref(), sri, to.as_ref()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hard links a cache entry by key to a specified location.
|
||||||
|
pub async fn hard_link<P, K, Q>(cache: P, key: K, to: Q) -> Result<()>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
K: AsRef<str>,
|
||||||
|
Q: AsRef<Path>,
|
||||||
|
{
|
||||||
|
async fn inner(cache: &Path, key: &str, to: &Path) -> Result<()> {
|
||||||
|
if let Some(entry) = index::find(cache, key)? {
|
||||||
|
read::hard_link_async(cache, &entry.integrity, to).await
|
||||||
|
} else {
|
||||||
|
Err(Error::EntryNotFound(cache.to_path_buf(), key.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inner(cache.as_ref(), key.as_ref(), to.as_ref()).await
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the metadata entry for a certain key.
|
/// Gets the metadata entry for a certain key.
|
||||||
///
|
///
|
||||||
/// Note that the existence of a metadata entry is not a guarantee that the
|
/// Note that the existence of a metadata entry is not a guarantee that the
|
||||||
|
|
@ -573,6 +590,55 @@ where
|
||||||
read::copy_unchecked(cache.as_ref(), sri, to.as_ref())
|
read::copy_unchecked(cache.as_ref(), sri, to.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hard links a cache entry by key to a specified location. The cache entry
|
||||||
|
/// contents will not be checked, and all the usual caveats of hard links
|
||||||
|
/// apply: The potentially-shared cache might be corrupted if the hard link is
|
||||||
|
/// modified.
|
||||||
|
pub fn hard_link_unchecked_sync<P, K, Q>(cache: P, key: K, to: Q) -> Result<()>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
K: AsRef<str>,
|
||||||
|
Q: AsRef<Path>,
|
||||||
|
{
|
||||||
|
fn inner(cache: &Path, key: &str, to: &Path) -> Result<()> {
|
||||||
|
if let Some(entry) = index::find(cache, key)? {
|
||||||
|
hard_link_hash_unchecked_sync(cache, &entry.integrity, to)
|
||||||
|
} else {
|
||||||
|
Err(Error::EntryNotFound(cache.to_path_buf(), key.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inner(cache.as_ref(), key.as_ref(), to.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hard links a cache entry by key to a specified location.
|
||||||
|
pub fn hard_link_sync<P, K, Q>(cache: P, key: K, to: Q) -> Result<()>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
K: AsRef<str>,
|
||||||
|
Q: AsRef<Path>,
|
||||||
|
{
|
||||||
|
fn inner(cache: &Path, key: &str, to: &Path) -> Result<()> {
|
||||||
|
if let Some(entry) = index::find(cache, key)? {
|
||||||
|
read::hard_link(cache, &entry.integrity, to)
|
||||||
|
} else {
|
||||||
|
Err(Error::EntryNotFound(cache.to_path_buf(), key.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inner(cache.as_ref(), key.as_ref(), to.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hard links a cache entry by integrity address to a specified location. The
|
||||||
|
/// cache entry contents will not be checked, and all the usual caveats of
|
||||||
|
/// hard links apply: The potentially-shared cache might be corrupted if the
|
||||||
|
/// hard link is modified.
|
||||||
|
pub fn hard_link_hash_unchecked_sync<P, Q>(cache: P, sri: &Integrity, to: Q) -> Result<()>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
Q: AsRef<Path>,
|
||||||
|
{
|
||||||
|
read::hard_link_unchecked(cache.as_ref(), sri, to.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets metadata for a certain key.
|
/// Gets metadata for a certain key.
|
||||||
///
|
///
|
||||||
/// Note that the existence of a metadata entry is not a guarantee that the
|
/// Note that the existence of a metadata entry is not a guarantee that the
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue