diff --git a/NEWS.md b/NEWS.md index 40d7f69b6..bfde8f25f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -24,6 +24,7 @@ v1.0.0 * Moved all resources to a subdirectory structure and enabled the CMake install prefix variable to generate the resources search path * Changed theme directory to the install prefix (e.g. /usr/local/share/emulationstation/themes) with themes in the home directory taking precedence * No more attempts to open files directly under /etc, instead only the install prefix directory and the home directory are used +* Added proper error handling for missing resource files and improved overall logging * Refactoring, cleanup and documentation of the source code, removal of deprecated files etc. * All required fonts bundled with the application, no dependencies on the OS to provide them any longer * Made pugixml an external dependency instead of bundling it diff --git a/es-app/src/SystemData.cpp b/es-app/src/SystemData.cpp index dab0443d7..dc9e28e17 100644 --- a/es-app/src/SystemData.cpp +++ b/es-app/src/SystemData.cpp @@ -94,8 +94,14 @@ void SystemData::setIsGameSystemStatus() bool SystemData::populateFolder(FileData* folder) { const std::string& folderPath = folder->getPath(); + if (!Utils::FileSystem::exists(folderPath)) { + LOG(LogInfo) << "Info - Folder with path \"" << + folderPath << "\" does not exist."; + return false; + } if (!Utils::FileSystem::isDirectory(folderPath)) { - LOG(LogWarning) << "Error - folder with path \"" << folderPath << "\" is not a directory!"; + LOG(LogWarning) << "Warning - Folder with path \"" << + folderPath << "\" is not a directory!"; return false; } @@ -104,7 +110,8 @@ bool SystemData::populateFolder(FileData* folder) // If this symlink resolves to somewhere that's at the beginning of our // path, it's going to create a recursive loop. Make sure to avoid this. if (folderPath.find(Utils::FileSystem::getCanonicalPath(folderPath)) == 0) { - LOG(LogWarning) << "Skipping infinitely recursive symlink \"" << folderPath << "\""; + LOG(LogWarning) << "Warning - Skipping infinitely recursive symlink \"" << + folderPath << "\""; return false; } } @@ -211,7 +218,7 @@ bool SystemData::loadConfig() LOG(LogInfo) << "Loading system config file " << path << "..."; if (!Utils::FileSystem::exists(path)) { - LOG(LogError) << "es_systems.cfg file does not exist!"; + LOG(LogError) << "Error - es_systems.cfg file does not exist!"; writeExampleConfig(getConfigPath(true)); return false; } @@ -220,7 +227,7 @@ bool SystemData::loadConfig() pugi::xml_parse_result res = doc.load_file(path.c_str()); if (!res) { - LOG(LogError) << "Could not parse es_systems.cfg file!"; + LOG(LogError) << "Error - Could not parse es_systems.cfg file!"; LOG(LogError) << res.description(); return false; } @@ -229,7 +236,7 @@ bool SystemData::loadConfig() pugi::xml_node systemList = doc.child("systemList"); if (!systemList) { - LOG(LogError) << "es_systems.cfg is missing the tag!"; + LOG(LogError) << "Error - es_systems.cfg is missing the tag!"; return false; } @@ -275,8 +282,8 @@ bool SystemData::loadConfig() // If there appears to be an actual platform ID supplied // but it didn't match the list, generate a warning. if (str != nullptr && str[0] != '\0' && platformId == PlatformIds::PLATFORM_UNKNOWN) - LOG(LogWarning) << "Unknown platform for system \"" << name << "\" (platform \"" - << str << "\" from list \"" << platformList << "\")"; + LOG(LogWarning) << "Warning - Unknown platform for system \"" << name << + "\" (platform \"" << str << "\" from list \"" << platformList << "\")"; else if (platformId != PlatformIds::PLATFORM_UNKNOWN) platformIds.push_back(platformId); } @@ -286,7 +293,7 @@ bool SystemData::loadConfig() // Validate. if (name.empty() || path.empty() || extensions.empty() || cmd.empty()) { - LOG(LogError) << "System \"" << name << + LOG(LogError) << "Error - System \"" << name << "\" is missing name, path, extension, or command!"; continue; } @@ -310,7 +317,7 @@ bool SystemData::loadConfig() SystemData* newSys = new SystemData(name, fullname, envData, themeFolder); if (newSys->getRootFolder()->getChildrenByFilename().size() == 0) { - LOG(LogWarning) << "System \"" << name << "\" has no games! Ignoring it."; + LOG(LogInfo) << "Info - System \"" << name << "\" has no games, ignoring it."; delete newSys; } else { diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index e6d0da892..6d03ee107 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -416,12 +416,18 @@ int main(int argc, char* argv[]) bool splashScreen = Settings::getInstance()->getBool("SplashScreen"); bool splashScreenProgress = Settings::getInstance()->getBool("SplashScreenProgress"); + SDL_Event event; if (!window.init()) { LOG(LogError) << "Window failed to initialize!"; return 1; } + InputManager::getInstance()->parseEvent(event, &window); + if (event.type == SDL_QUIT) + return 1; + + if (splashScreen) { std::string progressText = "Loading..."; if (splashScreenProgress) @@ -433,8 +439,7 @@ int main(int argc, char* argv[]) if (loadSystemConfigFile(errorMsg) != NO_ERRORS) { // Something went terribly wrong. - if (errorMsg == "") - { + if (errorMsg == "") { LOG(LogError) << "Unknown error occured while parsing system config file."; Renderer::deinit(); return 1; diff --git a/es-app/src/scrapers/GamesDBJSONScraper.cpp b/es-app/src/scrapers/GamesDBJSONScraper.cpp index e9458e07a..bde52ce95 100644 --- a/es-app/src/scrapers/GamesDBJSONScraper.cpp +++ b/es-app/src/scrapers/GamesDBJSONScraper.cpp @@ -161,8 +161,8 @@ void thegamesdb_generate_json_scraper_requests( first = false; } else { - LOG(LogWarning) << "TheGamesDB scraper warning - no support for platform " - << getPlatformName(*platformIt); + LOG(LogWarning) << "Warning - TheGamesDB scraper warning - " + "no support for platform " << getPlatformName(*platformIt); } } path += platformQueryParam; @@ -290,6 +290,7 @@ void processGame(const Value& game, std::vector& results) result.gameID = std::to_string(getIntOrThrow(game, "id")); result.mdl.set("name", getStringOrThrow(game, "game_title")); + if (game.HasMember("overview") && game["overview"].IsString()) result.mdl.set("desc", game["overview"].GetString()); @@ -309,6 +310,21 @@ void processGame(const Value& game, std::vector& results) if (game.HasMember("players") && game["players"].IsInt()) result.mdl.set("players", std::to_string(game["players"].GetInt())); + LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Name: " << + result.mdl.get("name"); + LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Release Date (unparsed): " << + game["release_date"].GetString(); + LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Release Date (parsed): " << + result.mdl.get("releasedate"); + LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Developer: " << + result.mdl.get("developer"); + LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Publisher: " << + result.mdl.get("publisher"); + LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Genre: " << + result.mdl.get("genre"); + LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Players: " << + result.mdl.get("players"); + result.mediaURLFetch = NOT_STARTED; results.push_back(result); } @@ -365,7 +381,7 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr& req, if (doc.HasParseError()) { std::string err = - std::string("TheGamesDBJSONRequest - Error parsing JSON. \n\t") + + std::string("Error - TheGamesDBJSONRequest - Error parsing JSON. \n\t") + GetParseError_En(doc.GetParseError()); setError(err); LOG(LogError) << err; @@ -384,7 +400,7 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr& req, baseImageUrlLarge = base_url["large"].GetString(); } else { - std::string warn = "TheGamesDBJSONRequest - No URL path for large images.\n"; + std::string warn = "Warning - TheGamesDBJSONRequest - No URL path for large images.\n"; LOG(LogWarning) << warn; return; } @@ -393,7 +409,7 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr& req, processMediaURLs(images, baseImageUrlLarge, results); } catch (std::runtime_error& e) { - LOG(LogError) << "Error while processing media URLs: " << e.what(); + LOG(LogError) << "Error - Error while processing media URLs: " << e.what(); } // Find how many more requests we can make before the scraper @@ -412,7 +428,7 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr& req, // These process steps are for the initial scraping response. if (!doc.HasMember("data") || !doc["data"].HasMember("games") || !doc["data"]["games"].IsArray()) { - std::string warn = "TheGamesDBJSONRequest - Response had no game data.\n"; + std::string warn = "Warning - TheGamesDBJSONRequest - Response had no game data.\n"; LOG(LogWarning) << warn; return; } @@ -426,7 +442,7 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr& req, processGame(v, results); } catch (std::runtime_error& e) { - LOG(LogError) << "Error while processing game: " << e.what(); + LOG(LogError) << "Error - Error while processing game: " << e.what(); } } } diff --git a/es-app/src/scrapers/Scraper.cpp b/es-app/src/scrapers/Scraper.cpp index 4f027c070..d51cb6270 100644 --- a/es-app/src/scrapers/Scraper.cpp +++ b/es-app/src/scrapers/Scraper.cpp @@ -29,7 +29,8 @@ std::unique_ptr startScraperSearch(const ScraperSearchParam // Check if the scraper in the settings still exists as a registered scraping source. if (scraper_request_funcs.find(name) == scraper_request_funcs.end()) - LOG(LogWarning) << "Configured scraper (" << name << ") unavailable, scraping aborted."; + LOG(LogWarning) << "Warning - Configured scraper (" << name << + ") unavailable, scraping aborted."; else scraper_request_funcs.at(name)(params, handle->mRequestQueue, handle->mResults); @@ -44,7 +45,8 @@ std::unique_ptr startMediaURLsFetch(const std::string& game ScraperSearchParams params; // Check if the scraper in the settings still exists as a registered scraping source. if (scraper_request_funcs.find(name) == scraper_request_funcs.end()) - LOG(LogWarning) << "Configured scraper (" << name << ") unavailable, scraping aborted."; + LOG(LogWarning) << "Warning - Configured scraper (" << name << + ") unavailable, scraping aborted."; else // Specifically use the TheGamesDB function as this type of request // will never occur for ScreenScraper. @@ -140,7 +142,7 @@ void ScraperHttpRequest::update() return; // Everything else is some sort of error. - LOG(LogError) << "ScraperHttpRequest network error (status: " << status<< ") - " + LOG(LogError) << "Error - ScraperHttpRequest network error (status: " << status<< ") - " << mReq->getErrorMsg(); setError(mReq->getErrorMsg()); } @@ -367,7 +369,7 @@ bool resizeImage(const std::string& path, int maxWidth, int maxHeight) if (format == FIF_UNKNOWN) format = FreeImage_GetFIFFromFilename(path.c_str()); if (format == FIF_UNKNOWN) { - LOG(LogError) << "Error - could not detect filetype for image \"" << path << "\"!"; + LOG(LogError) << "Error - Could not detect filetype for image \"" << path << "\"!"; return false; } @@ -376,7 +378,7 @@ bool resizeImage(const std::string& path, int maxWidth, int maxHeight) image = FreeImage_Load(format, path.c_str()); } else { - LOG(LogError) << "Error - file format reading not supported for image \"" << path << "\"!"; + LOG(LogError) << "Error - File format not supported for image \"" << path << "\"!"; return false; } @@ -397,7 +399,7 @@ bool resizeImage(const std::string& path, int maxWidth, int maxHeight) FreeImage_Unload(image); if (imageRescaled == nullptr) { - LOG(LogError) << "Could not resize image! (not enough memory? invalid bitdepth?)"; + LOG(LogError) << "Error - Could not resize image! (not enough memory? invalid bitdepth?)"; return false; } @@ -405,7 +407,7 @@ bool resizeImage(const std::string& path, int maxWidth, int maxHeight) FreeImage_Unload(imageRescaled); if (!saved) { - LOG(LogError) << "Failed to save resized image!"; + LOG(LogError) << "Error - Failed to save resized image!"; } return saved; diff --git a/es-app/src/scrapers/ScreenScraper.cpp b/es-app/src/scrapers/ScreenScraper.cpp index caac342c7..b38f2d1de 100644 --- a/es-app/src/scrapers/ScreenScraper.cpp +++ b/es-app/src/scrapers/ScreenScraper.cpp @@ -149,7 +149,7 @@ void screenscraper_generate_scraper_requests(const ScraperSearchParams& params, p_ids.push_back(mapIt->second); } else { - LOG(LogWarning) << "ScreenScraper: no support for platform " << + LOG(LogWarning) << "Warning - ScreenScraper: no support for platform " << getPlatformName(*platformIt); // Add the scrape request without a platform/system ID. requests.push(std::unique_ptr @@ -180,8 +180,7 @@ void ScreenScraperRequest::process(const std::unique_ptr& req, if (!parseResult) { std::stringstream ss; - ss << "ScreenScraperRequest - Error parsing XML." << std::endl << - parseResult.description() << ""; + ss << "Error - ScreenScraperRequest - Error parsing XML: " << parseResult.description(); std::string err = ss.str(); setError(err); @@ -232,14 +231,12 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc, // Genre fallback language: EN. ( Xpath: Data/jeu[0]/genres/genre[*] ). result.mdl.set("genre", find_child_by_attribute_list(game.child("genres"), "genre", "langue", { language, "en" }).text().get()); - LOG(LogDebug) << "Genre: " << result.mdl.get("genre"); // Get the date proper. The API returns multiple 'date' children nodes to the 'dates' // main child of 'jeu'. // Date fallback: WOR(LD), US, SS, JP, EU. std::string _date = find_child_by_attribute_list(game.child("dates"), "date", "region", { region, "wor", "us", "ss", "jp", "eu" }).text().get(); - LOG(LogDebug) << "Release Date (unparsed): " << _date; // Date can be YYYY-MM-DD or just YYYY. if (_date.length() > 4) { @@ -251,8 +248,6 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc, Utils::Time::stringToTime(_date, "%Y"))); } - LOG(LogDebug) << "Release Date (parsed): " << result.mdl.get("releasedate"); - /// Developer for the game( Xpath: Data/jeu[0]/developpeur ). std::string developer = game.child("developpeur").text().get(); if (!developer.empty()) @@ -276,6 +271,21 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc, result.mdl.set("rating", ss.str()); } + LOG(LogDebug) << "ScreenScraperRequest::processGame(): Name: " << + result.mdl.get("name"); + LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (unparsed): " << + _date; + LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (parsed): " << + result.mdl.get("releasedate"); + LOG(LogDebug) << "ScreenScraperRequest::processGame(): Developer: " << + result.mdl.get("developer"); + LOG(LogDebug) << "ScreenScraperRequest::processGame(): Publisher: " << + result.mdl.get("publisher"); + LOG(LogDebug) << "ScreenScraperRequest::processGame(): Genre: " << + result.mdl.get("genre"); + LOG(LogDebug) << "ScreenScraperRequest::processGame(): Players: " << + result.mdl.get("players"); + // Media super-node. pugi::xml_node media_list = game.child("medias"); @@ -352,13 +362,13 @@ void ScreenScraperRequest::processList(const pugi::xml_document& xmldoc, { assert(mRequestQueue != nullptr); - LOG(LogDebug) << "Processing a list of results"; + LOG(LogDebug) << "ScreenScraper: Processing a list of results"; pugi::xml_node data = xmldoc.child("Data"); pugi::xml_node game = data.child("jeu"); if (!game) { - LOG(LogDebug) << "Found nothing"; + LOG(LogDebug) << "ScreenScraper: Found nothing"; } ScreenScraperRequest::ScreenScraperConfig ssConfig; diff --git a/es-app/src/views/UIModeController.cpp b/es-app/src/views/UIModeController.cpp index 45ffbadc4..8cd506c0a 100644 --- a/es-app/src/views/UIModeController.cpp +++ b/es-app/src/views/UIModeController.cpp @@ -146,8 +146,8 @@ void UIModeController::logInput(InputConfig * config, Input input) mapname += ", "; } - LOG(LogDebug) << "UIModeController::logInput( " << config->getDeviceName() << - " ):" << input.string() << ", isMappedTo= " << mapname << ", value=" << input.value; + LOG(LogDebug) << "UIModeController::logInput(" << config->getDeviceName() << + "): " << input.string() << ", isMappedTo=" << mapname << ", value=" << input.value; } bool UIModeController::isValidInput(InputConfig * config, Input input) diff --git a/es-core/src/ImageIO.cpp b/es-core/src/ImageIO.cpp index 54c052673..5d3b8b764 100644 --- a/es-core/src/ImageIO.cpp +++ b/es-core/src/ImageIO.cpp @@ -65,7 +65,8 @@ std::vector ImageIO::loadFromMemoryRGBA32(const unsigned char * d } } else { - LOG(LogError) << "Error - File type " << + LOG(LogError) << "Error - Couldn't load image, file is missing or the file type is " << +// it's not existing or the file type " << (format == FIF_UNKNOWN ? "unknown" : "unsupported") << "!"; } // Free fiMemory again diff --git a/es-core/src/Platform.cpp b/es-core/src/Platform.cpp index 5999e252d..be4858e1f 100644 --- a/es-core/src/Platform.cpp +++ b/es-core/src/Platform.cpp @@ -5,7 +5,12 @@ // #include "Platform.h" + +#include "renderers/Renderer.h" #include "utils/StringUtil.h" +#include "AudioManager.h" +#include "Log.h" +#include "MameNames.h" #if defined(__linux__) || defined(_WIN64) #include @@ -22,8 +27,6 @@ #endif #include -#include "Log.h" - int runRebootCommand() { #ifdef _WIN64 // Windows. @@ -141,6 +144,19 @@ int quitES(QuitMode mode) return 0; } +void emergencyShutdown() +{ + LOG(LogError) << "Critical Error - Performing emergency shutdown..."; + + MameNames::deinit(); + AudioManager::getInstance()->deinit(); + // Most of the SDL deinitialization is done in Renderer. + Renderer::deinit(); + Log::flush(); + + exit(EXIT_FAILURE); +} + void touch(const std::string& filename) { #ifdef _WIN64 diff --git a/es-core/src/Platform.h b/es-core/src/Platform.h index 40c1992e4..987fe9adf 100644 --- a/es-core/src/Platform.h +++ b/es-core/src/Platform.h @@ -29,7 +29,10 @@ int runSystemCommand(const std::wstring& cmd_utf16); int launchEmulatorUnix(const std::string& cmd_utf8); int launchEmulatorWindows(const std::wstring& cmd_utf16); +// Clean, normal shutdown. int quitES(QuitMode mode = QuitMode::QUIT); +// Immediately shut down the application as cleanly as possible. +void emergencyShutdown(); void processQuitMode(); #endif // ES_CORE_PLATFORM_H diff --git a/es-core/src/renderers/Renderer.cpp b/es-core/src/renderers/Renderer.cpp index b0b5ce506..08b7ecf61 100644 --- a/es-core/src/renderers/Renderer.cpp +++ b/es-core/src/renderers/Renderer.cpp @@ -37,8 +37,8 @@ namespace Renderer { size_t width = 0; size_t height = 0; - ResourceData resData = - ResourceManager::getInstance()->getFileData(":/graphics/window_icon_256.png"); + ResourceData resData = ResourceManager::getInstance()-> + getFileData(":/graphics/window_icon_256.png"); std::vector rawData = ImageIO::loadFromMemoryRGBA32(resData.ptr.get(), resData.length, width, height); diff --git a/es-core/src/resources/Font.cpp b/es-core/src/resources/Font.cpp index f91c12762..69a077b17 100644 --- a/es-core/src/resources/Font.cpp +++ b/es-core/src/resources/Font.cpp @@ -213,6 +213,13 @@ std::vector getFallbackFontPaths() { std::vector fontPaths; + // Standard fonts, let's include them here for error checking purposes even though that's + // not really the correct location. (The application will crash if they are missing.) + ResourceManager::getInstance()-> + getResourcePath(":/fonts/opensans_hebrew_condensed_light.ttf"); + ResourceManager::getInstance()-> + getResourcePath(":/fonts/opensans_hebrew_condensed_regular.ttf"); + // Vera sans Unicode: fontPaths.push_back(ResourceManager::getInstance()-> getResourcePath(":/fonts/DejaVuSans.ttf")); diff --git a/es-core/src/resources/ResourceManager.cpp b/es-core/src/resources/ResourceManager.cpp index ff6586f6c..020e1250c 100644 --- a/es-core/src/resources/ResourceManager.cpp +++ b/es-core/src/resources/ResourceManager.cpp @@ -8,6 +8,10 @@ #include "ResourceManager.h" #include "utils/FileSystemUtil.h" +#include "Log.h" +#include "Platform.h" +#include "Scripting.h" + #include auto array_deleter = [](unsigned char* p) { delete[] p; }; @@ -31,23 +35,36 @@ std::string ResourceManager::getResourcePath(const std::string& path) const { // Check if this is a resource file. if ((path[0] == ':') && (path[1] == '/')) { - std::string test; + std::string testHome; + std::string testDataPath; // Check under the home directory. - test = Utils::FileSystem::getHomePath() + "/.emulationstation/resources/" + &path[2]; - if (Utils::FileSystem::exists(test)) - return test; + testHome = Utils::FileSystem::getHomePath() + "/.emulationstation/resources/" + &path[2]; + if (Utils::FileSystem::exists(testHome)) + return testHome; // Check for the resource under the data installation directory for Unix or under // the executable directory for Windows. #ifdef _WIN64 - test = Utils::FileSystem::getExePath() + "/resources/" + &path[2]; + testDataPath = Utils::FileSystem::getExePath() + "/resources/" + &path[2]; #else - test = Utils::FileSystem::getProgramDataPath() + "/resources/" + &path[2]; + testDataPath = Utils::FileSystem::getProgramDataPath() + "/resources/" + &path[2]; #endif - if (Utils::FileSystem::exists(test)) - return test; + if (Utils::FileSystem::exists(testDataPath)) { + return testDataPath; + } + // For missing resources, log an error and terminate the application. This should + // indicate that we have a broken EmulationStation installation. + else { + LOG(LogError) << "Error - Program resource missing: " << path; + LOG(LogError) << "Tried to find the resource in the following locations:"; + LOG(LogError) << testHome; + LOG(LogError) << testDataPath; + LOG(LogError) << "Has EmulationStation been properly installed?"; + Scripting::fireEvent("quit"); + emergencyShutdown(); + } } // Not a resource, return unmodified path. diff --git a/es-core/src/utils/FileSystemUtil.cpp b/es-core/src/utils/FileSystemUtil.cpp index 4a1225cca..271536cef 100644 --- a/es-core/src/utils/FileSystemUtil.cpp +++ b/es-core/src/utils/FileSystemUtil.cpp @@ -490,20 +490,19 @@ namespace Utils #if defined(_WIN64) HANDLE hFile = CreateFile(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); -/* - if (hFile != INVALID_HANDLE_VALUE) { - resolved.resize(GetFinalPathNameByHandle(hFile, nullptr, 0, - resolved.resize(GetFinalPathNameByHandle(hFile, nullptr, 0, - FILE_NAME_NORMALIZED) + 1); - if (GetFinalPathNameByHandle(hFile, (LPSTR)resolved.data(), - if (GetFinalPathNameByHandle(hFile, (LPSTR)resolved.data(), - (DWORD)resolved.size(), FILE_NAME_NORMALIZED) > 0) { - resolved.resize(resolved.size() - 1); - resolved = getGenericPath(resolved); - } - CloseHandle(hFile); - } -*/ +// TEMPORARY, will need to fix this later. +// if (hFile != INVALID_HANDLE_VALUE) { +// resolved.resize(GetFinalPathNameByHandle(hFile, nullptr, 0, +// resolved.resize(GetFinalPathNameByHandle(hFile, nullptr, 0, +// FILE_NAME_NORMALIZED) + 1); +// if (GetFinalPathNameByHandle(hFile, (LPSTR)resolved.data(), +// if (GetFinalPathNameByHandle(hFile, (LPSTR)resolved.data(), +// (DWORD)resolved.size(), FILE_NAME_NORMALIZED) > 0) { +// resolved.resize(resolved.size() - 1); +// resolved = getGenericPath(resolved); +// } +// CloseHandle(hFile); +// } #else struct stat info;