rikyoz / bit7z

A C++ static library offering a clean and simple interface to the 7-zip shared libraries.
https://rikyoz.github.io/bit7z
Mozilla Public License 2.0
650 stars 117 forks source link

v4.0.8 Windows - Unable to extract archive to a very long UNC path #240

Open dhananjay-gune opened 2 months ago

dhananjay-gune commented 2 months ago

bit7z v4.0.8, Win10, Visual Studio 2022 v17.11.2, C++17, x64

BitArchiveReader.extractTo() fails if the outDir is a very long UNC path e.g. 635 chars long.

BitException: Failed to open the output file: The filename, directory name, or volume label syntax is incorrect. errorCode = 123

ThefailedFiles() indicate that the file has a prefix \\?\
I presume this could be the cause of failure as this prefix seems to be designated for local drives only.
I suppose bit7z should apply the long-path-prefix designated for the UNC paths i.e. \\?\UNC\ as described here:
https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry

2024-09-03 00_27_43-Maximum Path Length Limitation - Win32 apps _ Microsoft Learn - Work - Microsoft

I could be wrong in my understanding about these prefixes!

But what I have observed is that fs::create_directories() with a long UNC path succeeds only if it has \\?\UNC\ prefix and not \\?\.
For a mapped network drive e.g. S:\...long path..., the regular prefix works i.e. \\?\

I use Win32 shlwapi.h -> PathIsUNC() to determine which prefix to apply.
https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-pathisuncw

Here is my sample code for your reference:

FS::path applyLongPathPrefix(const FS::path& pathToCheck)
{
    if (isLongPathPrefixRequired(pathToCheck))
    {
        auto isUnc = PathIsUNC(pathToCheck.c_str());
        if (isUnc)
        {
            FS::path longUNCPath(WIN_LONG_PATH_PREFIX_UNC); // R"(\\?\UNC\)"
            size_t index = 2;
            tstring removedFirst2Slashes = pathToCheck.native().substr(index); // from "\\ServerName\SharedFolder" returns "ServerName\\SharedFolder"
            longUNCPath += removedFirst2Slashes;
            return longUNCPath;
        }
        FS::path longPath(WIN_LONG_PATH_PREFIX_LOCALDRIVE); // R"(\\?\)"
        longPath += pathToCheck;
        return longPath;
    }
    return pathToCheck;
}

Thanks for your support! 🙏

rikyoz commented 2 months ago

Hi! Yeah, bit7z automatic path prefix doesn't support UNC paths. I'll fix this in the next v4.0.9. Thanks for pointing this out! 🙏