From 07c38414c765f93664e374b43f098d0957b245f4 Mon Sep 17 00:00:00 2001 From: OneSixForensics Date: Thu, 25 Jun 2026 09:10:29 -0600 Subject: [PATCH] fix(context): resolve files whose names contain glob metacharacters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context.get_source_file_path() verifies a candidate with Path(candidate).match(partial_path). Path.match is glob-based, so real filenames containing glob metacharacters ('[', ']', '*', '?') never match — e.g. "IMG_0347[1].jpg" or "[clips4sale.com]video.wmv", which are pervasive in real cloud/device-backup returns. check_in_media then logs "No matching file found" and registers no media for those files. The filename map is already keyed on the exact basename, so: - a single candidate is unambiguous and is returned directly (also the fast path), and - when several files share a basename, fall back to an exact path-suffix comparison after the existing Path.match attempt. Closes #286. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01BdD6DdQA21KqDRSUjQHaTK --- scripts/context.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/context.py b/scripts/context.py index bdf50aa..273b75a 100644 --- a/scripts/context.py +++ b/scripts/context.py @@ -318,9 +318,23 @@ def get_source_file_path(partial_path): if filename in lookup_map: candidate_paths = lookup_map[filename] + # The filename map already keyed on the exact basename, so a single + # candidate is unambiguous — return it without a pattern match. + if len(candidate_paths) == 1: + return candidate_paths[0] + # Multiple files share this basename; disambiguate by the fuller + # path. Path.match treats glob metacharacters ('[', ']', '*', '?') + # in the pattern as wildcards, so it fails for real filenames that + # contain them (e.g. "IMG_0347[1].jpg"). Try it first for backward + # compatibility, then fall back to an exact path-suffix comparison. for candidate in candidate_paths: if Path(candidate).match(partial_path): return candidate + norm = partial_path.replace('\\', '/') + for candidate in candidate_paths: + cand_norm = candidate.replace('\\', '/') + if cand_norm == norm or cand_norm.endswith('/' + norm): + return candidate return None