Skip to content

Commit 1550e8d

Browse files
committed
composefs: new method ensure_object_from_fd
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
1 parent b928c6b commit 1550e8d

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

crates/composefs/src/repository.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,38 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
526526
Ok(id)
527527
}
528528

529+
/// Store an object from a file descriptor, using reflink (FICLONE) when possible.
530+
///
531+
/// Tries FICLONE first for an instant copy-on-write clone (works when the
532+
/// source fd and the repository are on the same filesystem). Falls back to
533+
/// a buffered data copy using the caller-provided `buf`. Passing a large
534+
/// buffer avoids the small default used by `std::io::copy`.
535+
#[context("Ensuring object from fd exists in repository")]
536+
pub fn ensure_object_from_fd(
537+
&self,
538+
fd: OwnedFd,
539+
size: u64,
540+
buf: &mut [u8],
541+
) -> Result<ObjectID> {
542+
let tmpfile = self.create_object_tmpfile()?;
543+
let src = File::from(fd);
544+
let mut dst = File::from(tmpfile);
545+
546+
if rustix::fs::ioctl_ficlone(&dst, &src).is_err() {
547+
let mut src = src;
548+
loop {
549+
let n = src.read(buf).context("reading from source fd")?;
550+
if n == 0 {
551+
break;
552+
}
553+
dst.write_all(&buf[..n])
554+
.context("writing to repository tmpfile")?;
555+
}
556+
}
557+
558+
self.finalize_object_tmpfile(dst, size)
559+
}
560+
529561
#[context("Opening file '{filename}' with verity verification")]
530562
fn open_with_verity(&self, filename: &str, expected_verity: &ObjectID) -> Result<OwnedFd> {
531563
let fd = self

0 commit comments

Comments
 (0)