From adc8ee37becd7ae1ca153995f47679a01f954fd3 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com> Date: Thu, 6 Aug 2026 22:48:27 -0700 Subject: [PATCH] Say when an entry is omitted for not being a plain file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A symlink to a directory — a normal way to keep tens of gigabytes of streams off the system disk — was dropped from the plan silently. `entry.file_type()` reports the LINK, so such a subtree never enters `dirs`, and `metadata()` then follows it and reports a directory, so it fails the is_file() test and was skipped with nothing said. The result is the worst class this release exists to close: PLAYLIST and CLIPINF still synthesize, so the folder scans and enumerates titles, every clip resolves to no extents, the mux takes its clean-EOF path, and a near-empty MKV is written at exit 0. It is still skipped rather than followed — following link targets invites cycles and escapes from the folder — but at the same volume as the unrepresentable-name skip eight lines above. --- src/dirimage/layout.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/dirimage/layout.rs b/src/dirimage/layout.rs index 29fc571..4348be5 100644 --- a/src/dirimage/layout.rs +++ b/src/dirimage/layout.rs @@ -275,6 +275,27 @@ fn walk(dir: &Path, disc_path: &str, depth: u32, entries: &mut usize) -> Result< Err(e) => return Err(Error::from(e)), }; if !meta.is_file() { + // Not a plain file after following the link. The common case is + // a SYMLINK TO A DIRECTORY — a normal way to keep 40 GB of + // streams off the system disk — and `entry.file_type()` above + // reports the link, not the target, so such a subtree never + // enters `dirs` and is silently absent from the image. + // + // The result was the worst class this release exists to close: + // BDMV/PLAYLIST and CLIPINF still synthesize, so the folder + // scans and enumerates titles, every clip resolves to no + // extents, and the mux takes its clean-EOF path and writes a + // near-empty MKV at exit 0. + // + // It is still skipped rather than followed — following link + // targets invites cycles and escapes from the folder — but it + // is now SAID, at the same volume as the name-skip above. + tracing::warn!( + target: "freemkv::dirimage", + path = %child_path, + kind = if meta.is_dir() { "directory link" } else { "special file" }, + "entry is not a plain file; omitted from the image" + ); continue; } files.push(FileNode {