Skip to content

Commit 199313d

Browse files
committed
Fixed cryptic error with file paths with invalid characters
* The error was reported about not being able to convert a Unicode character to a multibyte character, which doesn't make much sense for UCS-2-to-UTF-8 conversion, but it turns out that file paths on Windows may contain malformed Unicode characters, which triggers this error. * This commit adds a simple ASCII conversion for a bad Unicode path, which makes it easier to troubleshoot these issues.
1 parent 7996975 commit 199313d

1 file changed

Lines changed: 30 additions & 1 deletion

File tree

src/file_tracker.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,10 +570,26 @@ void file_tracker_t::run(void)
570570
// characters reach this point, `C:\Users\X` and `C:\Users\x`
571571
// will be tracked as two different paths.
572572
//
573+
try {
573574
if(options.base_path.empty())
574575
filepath = dir_entry.path().u8string();
575576
else
576577
filepath = dir_entry.path().lexically_relative(options.base_path).u8string();
578+
}
579+
catch (const std::exception& error) {
580+
//
581+
// Windows may store file paths with invalid UCS-2 characters,
582+
// which fail to convert to UTF-8 paths. For example, a file
583+
// path may have a code point `\x1F7FB` in it, which doesn't
584+
// have any Unicode character assigned and cannot be converted
585+
// to a UTF-8 string.
586+
//
587+
// Clear the file name to indicate this condition and mangle
588+
// the file name for reporting purposes in the exception handler.
589+
//
590+
filepath.clear();
591+
throw;
592+
}
577593

578594
//
579595
// Attempt to find the file by its relative path first. For
@@ -746,7 +762,20 @@ void file_tracker_t::run(void)
746762
catch (const std::exception& error) {
747763
progress_info.failed_files++;
748764

749-
print_stream.error("Cannot process a file %s (%s)", filepath.c_str(), error.what());
765+
//
766+
// filepath is empty when the directory entry has a path that
767+
// cannot be converted to UTF-8. Use a crude ASCII conversion
768+
// and replace all non-ASCII characters with `?`, just to
769+
// identify which file we couldn't process.
770+
//
771+
if(filepath.empty()) {
772+
std::u16string filepath_u16 = dir_entry.path().u16string();
773+
std::transform(filepath_u16.begin(), filepath_u16.end(),
774+
std::back_inserter(filepath),
775+
[] (char16_t chr) -> char {return (chr >= ' ' && chr < '\x7f' ? static_cast<char>(chr) : '?');});
776+
}
777+
778+
print_stream.error("Cannot process file %s (%s)", filepath.c_str(), error.what());
750779

751780
// if we started a transaction, roll it back
752781
if(!sqlite3_get_autocommit(file_scan_db)) {

0 commit comments

Comments
 (0)