Skip to content

Commit 060acc9

Browse files
committed
tar: handle unknown file types from fuse-overlayfs
On FUSE, the dirent type may be unknown so we have to fallback to a `stat()` call. Fixes: https://github.com/jlebon/chunkah/issues/20 Assisted-by: Claude Opus 4.5
1 parent de0026e commit 060acc9

1 file changed

Lines changed: 20 additions & 3 deletions

File tree

src/tar.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ fn write_symlink_entry<W: Write>(
349349
}
350350

351351
fn write_oci_archive_to<W: Write>(oci_dir: &Dir, writer: W) -> Result<()> {
352+
use cap_std_ext::cap_std::fs::FileType as CapFileType;
352353
use cap_std_ext::dirext::CapStdExtDirExt;
353354
use std::ops::ControlFlow;
354355

@@ -379,13 +380,25 @@ fn write_oci_archive_to<W: Write>(oci_dir: &Dir, writer: W) -> Result<()> {
379380
oci_dir
380381
.walk(&config, |component| {
381382
let path = component.path;
382-
if component.file_type.is_dir() {
383+
// if the d_type is missing (e.g. fuse), fallback to `stat`
384+
// XXX: cap-std docs mention is_unknown() exists, but it doesn't; add it
385+
// XXX: though probably should extend WalkConfiguration to have a ensure_file_type bool
386+
let file_type = if component.file_type == CapFileType::unknown() {
387+
component
388+
.dir
389+
.symlink_metadata(component.filename)
390+
.with_context(|| format!("getting metadata for {}", path.display()))?
391+
.file_type()
392+
} else {
393+
component.file_type
394+
};
395+
if file_type.is_dir() {
383396
let mut header = dir_header.clone();
384397
// Tar directories need a trailing slash
385398
let path_str = format!("{}/", path.display());
386399
tar.append_data(&mut header, &path_str, std::io::empty())
387400
.with_context(|| format!("appending directory {}", path.display()))?;
388-
} else if component.file_type.is_file() {
401+
} else if file_type.is_file() {
389402
let content = component
390403
.dir
391404
.read(component.filename)
@@ -395,7 +408,11 @@ fn write_oci_archive_to<W: Write>(oci_dir: &Dir, writer: W) -> Result<()> {
395408
tar.append_data(&mut header, path, content.as_slice())
396409
.with_context(|| format!("appending {}", path.display()))?;
397410
} else {
398-
anyhow::bail!("unsupported file type for {}", path.display());
411+
anyhow::bail!(
412+
"unsupported file type for {} ({:?})",
413+
path.display(),
414+
file_type
415+
);
399416
}
400417
Ok::<_, anyhow::Error>(ControlFlow::Continue(()))
401418
})

0 commit comments

Comments
 (0)