4

Im trying to create all folder in a path that reach to a file, for that by a little search I found out about std::filesystem::create_directories its ok but the problem of using it is looks like its can't handle long paths with so many subfolders, for small path its working without any problem, but when I tested it with a path that have 14 subfolder and near 185 character it failed and give me the The filename or extension is too long. error
here is the code Im using so far:

void create_dirs(std::filesystem::path path)
{
    if (!std::filesystem::exists(path))
    {
        path.remove_filename(); // remove file name
        try
        {
            std::filesystem::create_directories(path); // create dirs
        }
        catch (std::filesystem::filesystem_error& e)
        {
            std::cerr << e.what() << std::endl;
        }
        
    }
}

so what can I do for this? and what is the best solution?

My OS: Windows

file-tracer
  • 329
  • 1
  • 7
  • 2
    I just tried creating one directory at a time ([like this](https://godbolt.org/z/4ahqd5M1z)) in Windows but that didn't help. :-( I tried with VS2019 and VS2022 Preview. I guess you'll have to resort to creating the path through the WinAPI. I think long paths _are_ supported natively if you use the `W`(ide) functions. – Ted Lyngmo Oct 08 '21 at 14:50
  • 1
    Create the path iteratively - for example if your path is `a/b/c` then first create `a` then change the current working directory into it, then create `b`, and change you current working directory into it etc. Use the `std:: filesystem::current_path` function to change the current working directory. – dlivshen Oct 08 '21 at 14:54
  • 2
    @dlivshen That's exactly what I did (code in the link above) - didn't help. Interesting info: [support-long-paths-by-default-in-vs-implementation](https://developercommunity.visualstudio.com/t/support-long-paths-by-default-in-vs-implementation/377910) - "_In Windows 10 releases more recent than the "Anniversary Update" you can manifest your application appropriately and enable the group policy setting that lets ordinary (non \\?\) paths be longer than MAX_PATH, and std::filesystem (but not std::experimental::filesystem) will honor that request (without disabling Win32 path normalization)._" – Ted Lyngmo Oct 08 '21 at 14:55
  • @TedLyngmo I'm trying to make the program compatible with all windows after **xp**, so I cant manifest my program to extend the max_path for only win10, I also found [maximum-file-path-limitation](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd) that I think can help me – file-tracer Oct 08 '21 at 15:46
  • 2
    I find it hard to believe that this code would fail with a length error on a path containing 185 characters, which is well below the `MAX_PATH` limit of 260 characters (actually 248 for directories). Do you have the same error if you prefix the path with ```\\?\```? In any case, the Win32 API has functions to create directories with missing subfolders, such as `SHCreateDirectory/Ex()`. – Remy Lebeau Oct 08 '21 at 16:57
  • @RemyLebeau its strange for me too, because the biggest file path that I have is 225 char (+the file name inside it), it should create them without any problem, but its fail like this... I don't know what could be the problem... – file-tracer Oct 08 '21 at 17:06
  • 1
    @file-tracer Can you provide a [mcve] of that? Using both `std::filesystem` and Win32 APIs? Does it fail on a specific folder every time? Creating such a short path should not be causing a `"The filename or extension is too long"` error (error code 206, aka `ERROR_FILENAME_EXCED_RANGE`) - unless maybe the path in question contains sub-folders whose names are expanded inside the system to longer names, thus exceeding the max path allowed? – Remy Lebeau Oct 08 '21 at 17:20
  • @RemyLebeau oh I missed something, my path is 225 by itself, but when its add to root directory that I want all path to store to, it will become more then 255... (I mean if I have a path like `path/path2/path3/...` I want to store it to a other folder (as a root) so its become for ex. `D:/Project/output/other/.../path/path2/path3/...` and this make it pass MAX_PATH limit), I need to firstly set the root folder to my working directory I think... but what is the right way to it? should I use filesystem for it too? – file-tracer Oct 08 '21 at 17:40
  • @file-tracer In that case, the absolute path you are trying to create is simply just too long once the pieces are combined. So now the error makes sense. To work with such long paths, you MUST either 1) use the ```\\?\``` prefix with Win32 Unicode APIs (does `std::filesystem` use them internally), or else 2) on Windows 10 v1607+ and later only, [disable the `MAX_PATH` limitation](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later) via policy edits and manifestation. – Remy Lebeau Oct 08 '21 at 17:45
  • I set the current directory with `std::filesystem::current_path` to root of where I want to all folders create, but still its gave me the same error... should I use other function to set the current working path? other thing how exactly I can use **\\?\** with filesystem? I read I should use it like this `\\?\D:\very long path` but how can I use it in filesystem? – file-tracer Oct 08 '21 at 17:49
  • @file-tracer It doesn't matter where you set the CWD to point at, the TOTAL absolute path of root path + relative path (including null terminator) cannot exceed `MAX_PATH-12` characters, unless you explicitly tell the system otherwise. Yes, use `"\\?\D:\very long path..."`, you should be able to pass that to any `std::filesystem` methods that accepts a path string as an input parameter, provided the library implementation is using Win32 Unicode APIs internally. If it doesn't, well then you are SOL using `std::filesystem`, use the Unicode APIs directly instead. – Remy Lebeau Oct 08 '21 at 17:50
  • @RemyLebeau thank you very much, just one another noob question, how can I append \\?\ to a variable that have my path in it, I know I cant use something like `std::string fix_path = "\\\\?\\" + path;` – file-tracer Oct 08 '21 at 17:57
  • 1
    @file-tracer Actually yes, that is exactly what you can do. Though, I would suggest using a UTF-16 encoded `std::wstring` instead, unless the `std::string` is encoded as UTF-8 and you are passing it to a library/API that is expecting a UTF-8 string. Unicode APIs on Windows are `wchar_t` based. `std::filesystem::path` will accept either string type as input, but on Windows its `native_type` is `wchar_t` and its `string_type` is `std::wstring`, so it will have to perform a data conversion if you give it something else. – Remy Lebeau Oct 08 '21 at 18:11
  • @RemyLebeau but look like this method wont work, its just say `create_directories: The system cannot find the file specified.: "\\?\G:/Project/...` – file-tracer Oct 08 '21 at 18:47
  • 1
    oh nvm, its because of the `/` – file-tracer Oct 08 '21 at 18:50
  • 1
    Per [Maximum Path Length Limitation](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation): "*File I/O functions in the Windows API convert "/" to "\" as part of converting the name to an NT-style name, **except when using the "\\?\" prefix** ...*" – Remy Lebeau Oct 08 '21 at 18:55
  • 1
    seems like my problem solved with `std::filesystem::create_directories("\\\\?\\" + std::filesystem::absolute(path).string())`, if you like please add your solution as and answer, so I can accept it. – file-tracer Oct 08 '21 at 18:58
  • 2
    This sounds like the core issue here was, that you were using path separators that aren't actually path separators. A [mcve] would have made this far easier to see. – IInspectable Oct 09 '21 at 07:50
  • @IInspectable no the real reason was my path was bigger then 248... so the filesystem cant create it (really such a strange limitation that window have...) but my problem fixed by using \\?\ before the path, I'm just curios to know one thing, this (\\?\) is alliable in what window version? because my program target all window after XP (include itself). – file-tracer Oct 09 '21 at 10:02
  • I doubt that. Assuming NTFS, the file system imposes two limits: path names must be shorter than 32768 characters, and each path component must be shorter than 256 characters. You're probably exceeding the latter by supplying forward slashes, and the library unconditionally prepending the `\\?\\`` prefix, turning the forward slashes into regular characters. The `\\?\\`` prefix has been supported at least since Windows 2000. – IInspectable Oct 11 '21 at 16:01

0 Answers0