BOOL __stdcall FindNextFileFixup()

in fixups/FileRedirectionFixup/FindFirstFileFixup.cpp [343:542]


BOOL __stdcall FindNextFileFixup(_In_ HANDLE findFile, _Out_ win32_find_data_t<CharT>* findFileData) noexcept try
{
    auto guard = g_reentrancyGuard.enter();
    if (!guard)
    {
        Log(L"FindNextFileFixup for file.");

        return impl::FindNextFile(findFile, findFileData);
    }

    DWORD FindNextFileInstance = ++g_FileIntceptInstance;

    Log(L"[%d]FindNextFileFixup.", FindNextFileInstance);


    if (findFile == INVALID_HANDLE_VALUE)
    {
        ::SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    auto data = reinterpret_cast<find_data*>(findFile);
#if !_DEBUG
    Log(L"[%d]FindNextFileFixup is against redir  =%ls", FindNextFileInstance, data->redirect_path.c_str());
    Log(L"[%d]FindNextFileFixup is against pkgVfs =%ls", FindNextFileInstance, data->package_vfs_path.c_str());
    Log(L"[%d]FindNextFileFixup is against request=%ls", FindNextFileInstance, data->requested_path.c_str());
#endif

    auto redirectedFileExists = [&](auto filename)
    {
        if (data->redirect_path.empty())
        {
            Log(L"[%d]FindNextFile redirectedFileExists returns false.", FindNextFileInstance);
            return false;
        }

        auto revertSize = data->redirect_path.length();

        // NOTE: 'is_ansi' evaluation not inline due to the bug:
        //       https://developercommunity.visualstudio.com/content/problem/324366/illegal-indirection-error-when-the-evaluation-of-i.html
        constexpr bool is_ansi = psf::is_ansi<std::decay_t<decltype(*filename)>>;
        if constexpr (is_ansi)
        {
            data->redirect_path += widen(filename);
        }
        else
        {
            data->redirect_path += filename;
        }

        auto result = impl::PathExists(data->redirect_path.c_str());
        data->redirect_path.resize(revertSize);
        Log(L"[%d]FindNextFile redirectedFileExists returns %ls", FindNextFileInstance, data->redirect_path.c_str());
        return result;
    };
    auto vfspathFileExists = [&](auto filename)
    {
        if (data->package_vfs_path.empty())
        {
            Log(L"[%d]FindNextFile vfspathFileExists returns false.", FindNextFileInstance);
            return false;
        }

        auto revertSize = data->package_vfs_path.length();

        // NOTE: 'is_ansi' evaluation not inline due to the bug:
        //       https://developercommunity.visualstudio.com/content/problem/324366/illegal-indirection-error-when-the-evaluation-of-i.html
        constexpr bool is_ansi = psf::is_ansi<std::decay_t<decltype(*filename)>>;
        if constexpr (is_ansi)
        {
            data->package_vfs_path += widen(filename);
        }
        else
        {
            data->package_vfs_path += filename;
        }

        auto result = impl::PathExists(data->package_vfs_path.c_str());
        data->package_vfs_path.resize(revertSize);
        Log(L"[%d]FindNextFile vfspathFileExists returns %ls", FindNextFileInstance, data->package_vfs_path.c_str());
        return result;
    };

    if (!data->redirect_path.empty())
    {
        if (data->find_handles[0])
        {
            Log(L"[%d]FindNextFile[0] to be checked.", FindNextFileInstance);
            if (impl::FindNextFile(data->find_handles[0].get(), findFileData))
            {
                Log(L"[%d]FindNextFile[0] returns TRUE: %ls", FindNextFileInstance, data->cached_data.cFileName);
                return TRUE;
            }
            else if (::GetLastError() == ERROR_NO_MORE_FILES)
            {
                Log(L"[%d]FindNextFile[0] had FALSE with ERROR_NO_MORE_FILES.", FindNextFileInstance);
                data->find_handles[0].reset();

                if (data->package_vfs_path.empty() || !data->find_handles[1])
                {
                    Log(L"[%d]FindNextFile[1] not in use.", FindNextFileInstance);
                    if (data->requested_path.empty() || !data->find_handles[2])
                    {
                        Log(L"[%d]FindNextFile[2] not in use, so return ERROR_NO_MORE_FILES.", FindNextFileInstance);
                        // NOTE: Last error scribbled over by closing find_handles[0]
                        ::SetLastError(ERROR_NO_MORE_FILES);
                        return FALSE;
                    }
                    // else check[1]
                }

                if (!redirectedFileExists(data->cached_data.cFileName))
                {
                    if (copy_find_data(data->cached_data, *findFileData))
                    {
                        Log(L"[%d]FindNextFile[0] returns FALSE with last error set by caller", FindNextFileInstance);
                        // NOTE: Last error set by caller
                        return FALSE;
                    }

                    LogString(FindNextFileInstance, L"FindNextFile[0] returns TRUE with ERROR_SUCCESS and file %ls", data->cached_data.cFileName);
                    ::SetLastError(ERROR_SUCCESS);
                    return TRUE;
                }
            }
            else
            {
                // Error due to something other than reaching the end 
                Log(L"[%d]FindNextFile[0] returns FALSE", FindNextFileInstance);
                return FALSE;
            }
        }
    }

    if (!data->package_vfs_path.empty())
    {
        while (data->find_handles[1])
        {
            if (impl::FindNextFile(data->find_handles[1].get(), findFileData))
            {
                // Skip the file if it exists in the redirected path
                if (!redirectedFileExists(findFileData->cFileName))
                {
                    LogString(FindNextFileInstance, L"FindNextFile[1] returns TRUE with ERROR_SUCCESS and %ls", findFileData->cFileName);
                    ::SetLastError(ERROR_SUCCESS);
                    return TRUE;
                }
                // Otherwise, skip this file and check the next one
            }
            else if (::GetLastError() == ERROR_NO_MORE_FILES)
            {
                Log(L"[%d]FindNextFile[1] returns FALSE with ERROR_NO_MORE_FILES_FOUND.", FindNextFileInstance);
                data->find_handles[1].reset();
                // now check [2]
            }
            else
            {
                Log(L"[%d]FindNextFile[1] returns FALSE", FindNextFileInstance);
                // Error due to something other than reaching the end
                return FALSE;
            }
        }
    }

    if (!data->requested_path.empty())
    {
        while (data->find_handles[2])
        {
            if (impl::FindNextFile(data->find_handles[2].get(), findFileData))
            {
                // Skip the file if it exists in the redirected path
                if (!redirectedFileExists(findFileData->cFileName) &&
                    !vfspathFileExists(findFileData->cFileName))
                {
                    LogString(FindNextFileInstance, L"FindNextFile[2] returns TRUE with ERROR_SUCCESS and %ls", findFileData->cFileName);
                    ::SetLastError(ERROR_SUCCESS);
                    return TRUE;
                }
                // Otherwise, skip this file and check the next one
            }
            else if (::GetLastError() == ERROR_NO_MORE_FILES)
            {
                Log(L"[%d]FindNextFile[2] returns FALSE with ERROR_NO_MORE_FILES_FOUND.", FindNextFileInstance);
                data->find_handles[2].reset();
                ::SetLastError(ERROR_NO_MORE_FILES);
                return FALSE;
            }
            else
            {
                Log(L"[%d]FindNextFile[2] returns FALSE", FindNextFileInstance);
                // Error due to something other than reaching the end
                return FALSE;
            }
        }
    }
    // We ran out of data either on a previous call, or by ignoring files that have been redirected
    ::SetLastError(ERROR_NO_MORE_FILES);
    return FALSE;

}