1

I was working on a bigger project using the recursive_directory_iterator of std::filesystem, when I stumbled upon this seemingly unknown/unfixable error.

I simplified the project to the bare minimum to recreate the error. Another questioner found a solution in providing the skip_permission_denied option, which does nothing for me.

The exception is not limited to this file, it happens for random other files too, if I delete this one, for instance. Though it occurs for the same file every time if I decide not to delete it.

If I use the continue button on Visual Studio three times, it is actually able to continue the traversal of files.

What would be a proper way to address this error? And what could potentially cause this?

I removed all exception handling for readability, but the error occurs at the start of the for loop once it reaches this file.

#define NOMINMAX

#include <string>
#include <iostream>
#include <filesystem>
#include <windows.h>
#include <fstream>
#include <winbase.h>
#include <numeric>
#include <string_view>
#include <vector>
#include <shlobj_core.h>
//#include <combaseapi.h>

namespace fs = std::filesystem;

using namespace std;



void startWinXSearch(string argv)
{
    string pathToFolder = argv;

    cout << pathToFolder << endl;

    for (auto& el : std::filesystem::recursive_directory_iterator(pathToFolder, std::filesystem::directory_options::skip_permission_denied)) {
        cout << el << endl;
    }
}

int main(int argc, char* argv[])
{
    CoInitializeEx(NULL, COINIT_MULTITHREADED);

    string test = "C:\\Sciebo";

    startWinXSearch(test);


}

The Exception thrown

UPDATE: This is what I get from using wcout. No idea what this is supposed to mean. Is it that there's an invisible file there?! The Error thrown currently is No mapping for the Unicode character exists in the target multi-byte code page. If I find a solution or workaround I'll update it here.

last cout i get from using wcout

FINAL UPDATE: I got it. Take a look at one of the comments ^^ It originated from invisible Unicode characters infront of a random file from my phone :D I even got a fix/workaround for it!

Gisbert12843
  • 76
  • 1
  • 10

3 Answers3

1

Clearly you are getting a non-permission failure on some of the files. So, you will need to either:

  • wrap the failing code in a try..catch, eg:
#define NOMINMAX

#include <string>
#include <iostream>
#include <filesystem>

#include <windows.h>
#include <shlobj_core.h>
//#include <combaseapi.h>

namespace fs = std::filesystem;

void startWinXSearch(const std::string &pathToFolder)
{
    std::cout << pathToFolder << std::endl;

    try {
        for (auto& el : fs::recursive_directory_iterator(pathToFolder, fs::directory_options::skip_permission_denied)) {
            std::cout << el << std::endl;
        }
    }
    catch (const fs::filesystem_error &) {
        // handle error as needed...
    }
}

int main()
{
    CoInitializeEx(NULL, COINIT_MULTITHREADED);

    startWinXSearch("C:\\Sciebo");

    CoUninitialize();
}
  • use recursive_directory_iterator's non-throwing constructor and increment() method (which means you can't use a range-for loop), eg:
#define NOMINMAX

#include <string>
#include <iostream>
#include <filesystem>

#include <windows.h>
#include <shlobj_core.h>
//#include <combaseapi.h>

namespace fs = std::filesystem;

void startWinXSearch(const std::string &pathToFolder)
{
    std::cout << pathToFolder << std::endl;

    std::error_code ec;
    fs::recursive_directory_iterator dir(pathToFolder, fs::directory_options::skip_permission_denied, ec);

    if (ec) {
        // handle error as needed...
    }
    else {
        auto iter = std::begin(dir);
        auto iter_end = std::end(dir);

        while (iter != iter_end) {
            std::cout << *iter << std::endl;
            iter.increment(ec);
            if (ec) {
                // handle error as needed...
            }
        }
    }
}

int main()
{
    CoInitializeEx(NULL, COINIT_MULTITHREADED);

    startWinXSearch("C:\\Sciebo");

    CoUninitialize();
}

Either way, you can then analyze the fs::filesystem_error or std::error_code to find out what kind of OS error is actually occurring.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • how would i go about handling this error in the if(ec) sections? I tried all the codes provided and even renamed the files but the error seems to occurr after a certain time no matter the file name.. its not caused by unicode characters in the filename either. – Gisbert12843 Aug 09 '22 at 11:43
  • @Gisbert12843 "*how would i go about handling this error in the if(ec) sections?*" - well, for starters, by logging all of the error details and path that failed, so you can figure out what is actually going wrong, before you decide what (if anything) you can do to fix/ignore it. – Remy Lebeau Aug 09 '22 at 15:42
  • i put the while loop from your code in an try catch statement.. when i cout the exception i get: "No mapping for the Unicode character exists in the target multi-byte code page" as the prone exception".. i will google how to deal with that myself.. if you got any experience on that topic i would highly appreciate it! I even tried to use disable_recursion_pending() :D but that just stopped the process.. it also seems that it always gets to the end of the folder shown above and only then breaks.. there are dozens of folders it goes through before though.. – Gisbert12843 Aug 09 '22 at 22:12
1

Seems to be this error:

ERROR_NO_UNICODE_TRANSLATION

1113 (0x459)

No mapping for the Unicode character exists in the target multi-byte code page.

System Error Codes (1000-1299) (WinError.h) - Win32 apps | Microsoft Docs

Try renaming the file.

krisz
  • 2,686
  • 2
  • 11
  • 18
  • edit: ok it could very well be a unicode problem! since the file won't be proccessed it will never reach the cout section and by that won't show up! im to lazy to go through thousands of files by hand in debug mode sadly :D but i will try to find a solution since there are some redudant posts about this problem regarding the recursive iterator of std::filesystem ^^ – Gisbert12843 Aug 09 '22 at 11:58
  • Have you tried using `std::wcout` yet? `fs::(recursive_)directory_iterator` and `fs::directory_entry` do support Unicode `path`s, you don't have to use `std::string` with them. – Remy Lebeau Aug 09 '22 at 15:43
  • i tried it yes ^^ i get one more folder shown before it breaks.. i put the console log below my question :) it provides more questions than answers sadly.. – Gisbert12843 Aug 09 '22 at 22:19
0

SOOOOOOO

I got the answer.. The problem originates from invisible (atleast for win10) unicode characters infront of a file ^^

How do you prevent that from crashing your programm? EZ, we first build our iterating for loop. EG like this:

for (auto& dirEntry : fs::recursive_directory_iterator(pathToFolder))
// Iterates over every file/folder in the path of the executable and its subdiretories
{

    const std::wstring currentPath = dirEntry.path().c_str();

    string output = wide_string_to_string(currentPath);

    std::cout << output << endl;
}

Then we require a suited and well done wstring -> string conversion ^^ I got this one from some site I just can't find again..

std::string wide_string_to_string(const std::wstring& wide_string)
{
    if (wide_string.empty())
    {
        return "";
    }

    const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, &wide_string.at(0), (int)wide_string.size(), nullptr, 0, nullptr, nullptr);
    if (size_needed <= 0)
    {
        throw std::runtime_error("WideCharToMultiByte() failed: " + std::to_string(size_needed));
    }

    std::string result(size_needed, 0);
    WideCharToMultiByte(CP_UTF8, 0, &wide_string.at(0), (int)wide_string.size(), &result.at(0), size_needed, nullptr, nullptr);
    return result;
}

Our Main would look something like this.

int main()
{
    CoInitializeEx(NULL, COINIT_MULTITHREADED);

    startWinXSearch("C:\\Users\\wwwgi\\OneDrive\\Dokumente\\test");

    CoUninitialize();
}

Ofc you can also work with argv values, you just gotta format the raw path the appropiate way ^^ you can even use wmain + wchar_t argv[] if you like that! If you are unsure about the formatting you can try to format it with .path() and .string()/.c_string() :)

Gisbert12843
  • 76
  • 1
  • 10