From a225426510fc25316b3868e8764893dff284e77e Mon Sep 17 00:00:00 2001 From: comex Date: Sat, 15 Nov 2014 15:46:40 -0500 Subject: [PATCH 1/9] Rewrite FileSearch and improve ScanDirectoryTree. - FileSearch is now just one function, and it converts the original glob into a regex on all platforms rather than relying on native Windows pattern matching on there and a complete hack elsewhere. It now supports recursion out of the box rather than manually expanding into a full list of directories in multiple call sites. - This adds a GCC >= 4.9 dependency due to older versions having outright broken . MSVC is fine with it. - ScanDirectoryTree returns the parent entry rather than filling parts of it in via reference. The count is now stored in the entry like it was for subdirectories. - .glsl file search is now done with DoFileSearch. - IOCTLV_READ_DIR now uses ScanDirectoryTree directly and sorts the results after replacements for better determinism. --- Source/Core/Common/FileSearch.cpp | 121 ++++++------------ Source/Core/Common/FileSearch.h | 17 +-- Source/Core/Common/FileUtil.cpp | 75 ++++++----- Source/Core/Common/FileUtil.h | 5 +- Source/Core/Core/HW/GCMemcardDirectory.cpp | 13 +- Source/Core/Core/HW/WiiSaveCrypted.cpp | 6 +- .../Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp | 48 +++---- Source/Core/DiscIO/VolumeDirectory.cpp | 14 +- Source/Core/DiscIO/VolumeDirectory.h | 4 +- .../Core/DolphinQt/GameList/GameTracker.cpp | 45 ++----- Source/Core/DolphinQt/GameList/GameTracker.h | 2 +- .../DolphinWX/Config/InterfaceConfigPane.cpp | 10 +- Source/Core/DolphinWX/FrameTools.cpp | 10 +- Source/Core/DolphinWX/GameListCtrl.cpp | 33 +---- Source/Core/DolphinWX/InputConfigDiag.cpp | 14 +- Source/Core/VideoBackends/OGL/main.cpp | 45 ++----- Source/Core/VideoCommon/HiresTextures.cpp | 42 +----- 17 files changed, 156 insertions(+), 348 deletions(-) diff --git a/Source/Core/Common/FileSearch.cpp b/Source/Core/Common/FileSearch.cpp index 6170d3de2b..32bffa8ed7 100644 --- a/Source/Core/Common/FileSearch.cpp +++ b/Source/Core/Common/FileSearch.cpp @@ -2,101 +2,60 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#if !__clang__ && __GNUC__ == 4 && __GNUC_MINOR__ < 9 +#error is broken in GCC < 4.9; please upgrade +#endif + #include -#include +#include +#include #include "Common/CommonPaths.h" #include "Common/FileSearch.h" -#include "Common/StringUtil.h" +#include "Common/FileUtil.h" -#ifndef _WIN32 -#include -#else -#include -#endif - - -CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories) +static std::vector FileSearchWithTest(const std::vector& directories, bool recursive, std::function callback) { - // Reverse the loop order for speed? - for (auto& _rSearchString : _rSearchStrings) + std::vector result; + for (const std::string& directory : directories) { - for (auto& _rDirectory : _rDirectories) - { - FindFiles(_rSearchString, _rDirectory); - } + File::FSTEntry top = File::ScanDirectoryTree(directory, recursive); + + std::function DoEntry; + DoEntry = [&](File::FSTEntry& entry) { + if (callback(entry)) + result.push_back(entry.physicalName); + for (auto& child : entry.children) + DoEntry(child); + }; + DoEntry(top); } + // remove duplicates + std::sort(result.begin(), result.end()); + result.erase(std::unique(result.begin(), result.end()), result.end()); + return result; } - -void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath) +std::vector DoFileSearch(const std::vector& globs, const std::vector& directories, bool recursive) { - std::string GCMSearchPath; - BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); -#ifdef _WIN32 - WIN32_FIND_DATA findData; - HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData); - - if (FindFirst != INVALID_HANDLE_VALUE) + std::string regex_str = "^("; + for (const auto& str : globs) { - bool bkeepLooping = true; - - while (bkeepLooping) - { - if (findData.cFileName[0] != '.') - { - std::string strFilename; - BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName)); - m_FileNames.push_back(strFilename); - } - - bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false; - } + if (regex_str.size() != 2) + regex_str += "|"; + // convert glob to regex + regex_str += std::regex_replace(std::regex_replace(str, std::regex("\\."), "\\."), std::regex("\\*"), ".*"); } - FindClose(FindFirst); - - -#else - // TODO: super lame/broken - - auto end_match(_searchString); - - // assuming we have a "*.blah"-like pattern - if (!end_match.empty() && end_match[0] == '*') - end_match.erase(0, 1); - - // ugly - if (end_match == ".*") - end_match.clear(); - - DIR* dir = opendir(_strPath.c_str()); - - if (!dir) - return; - - while (auto const dp = readdir(dir)) - { - std::string found(dp->d_name); - - if ((found != ".") && (found != "..") && - (found.size() >= end_match.size()) && - std::equal(end_match.rbegin(), end_match.rend(), found.rbegin())) - { - std::string full_name; - if (_strPath.c_str()[_strPath.size() - 1] == DIR_SEP_CHR) - full_name = _strPath + found; - else - full_name = _strPath + DIR_SEP + found; - - m_FileNames.push_back(full_name); - } - } - - closedir(dir); -#endif + regex_str += ")$"; + std::regex regex(regex_str); + return FileSearchWithTest(directories, recursive, [&](const File::FSTEntry& entry) { + return std::regex_match(entry.virtualName, regex); + }); } -const CFileSearch::XStringVector& CFileSearch::GetFileNames() const +std::vector FindSubdirectories(const std::vector& directories, bool recursive) { - return m_FileNames; + return FileSearchWithTest(directories, true, [&](const File::FSTEntry& entry) { + return entry.isDirectory; + }); } diff --git a/Source/Core/Common/FileSearch.h b/Source/Core/Common/FileSearch.h index 9820f1db05..cb15f84799 100644 --- a/Source/Core/Common/FileSearch.h +++ b/Source/Core/Common/FileSearch.h @@ -7,18 +7,5 @@ #include #include -class CFileSearch -{ -public: - typedef std::vectorXStringVector; - - CFileSearch(const XStringVector& _rSearchStrings, const XStringVector& _rDirectories); - const XStringVector& GetFileNames() const; - -private: - - void FindFiles(const std::string& _searchString, const std::string& _strPath); - - XStringVector m_FileNames; -}; - +std::vector DoFileSearch(const std::vector& globs, const std::vector& directories, bool recursive = false); +std::vector FindSubdirectories(const std::vector& directories, bool recursive); diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 6e721b9766..980821e010 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -453,11 +453,14 @@ bool CreateEmptyFile(const std::string &filename) // Scans the directory tree gets, starting from _Directory and adds the // results into parentEntry. Returns the number of files+directories found -u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) +FSTEntry ScanDirectoryTree(const std::string &directory, bool recursive) { INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str()); // How many files + directories we found - u32 foundEntries = 0; + FSTEntry parent_entry; + parent_entry.physicalName = directory; + parent_entry.isDirectory = true; + parent_entry.size = 0; #ifdef _WIN32 // Find the first file in the directory. WIN32_FIND_DATA ffd; @@ -466,59 +469,55 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) if (hFind == INVALID_HANDLE_VALUE) { FindClose(hFind); - return foundEntries; + return parent_entry; } // Windows loop do { - FSTEntry entry; - const std::string virtualName(TStrToUTF8(ffd.cFileName)); + const std::string virtual_name(TStrToUTF8(ffd.cFileName)); #else struct dirent dirent, *result = nullptr; DIR *dirp = opendir(directory.c_str()); if (!dirp) - return 0; + return parent_entry; - // non Windows loop - while (!readdir_r(dirp, &dirent, &result) && result) - { - FSTEntry entry; - const std::string virtualName(result->d_name); -#endif - // check for "." and ".." - if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || - ((virtualName[0] == '.') && (virtualName[1] == '.') && - (virtualName[2] == '\0'))) - continue; - entry.virtualName = virtualName; - entry.physicalName = directory; - entry.physicalName += DIR_SEP + entry.virtualName; - - if (IsDirectory(entry.physicalName)) + // non Windows loop + while (!readdir_r(dirp, &dirent, &result) && result) { - entry.isDirectory = true; - // is a directory, lets go inside - entry.size = ScanDirectoryTree(entry.physicalName, entry); - foundEntries += (u32)entry.size; - } - else - { // is a file - entry.isDirectory = false; - entry.size = GetSize(entry.physicalName.c_str()); - } - ++foundEntries; - // Push into the tree - parentEntry.children.push_back(entry); -#ifdef _WIN32 - } while (FindNextFile(hFind, &ffd) != 0); + const std::string virtual_name(result->d_name); + #endif + if (virtual_name == "." || virtual_name == "..") + continue; + auto physical_name = directory + DIR_SEP + virtual_name; + FSTEntry entry; + entry.isDirectory = IsDirectory(physical_name); + if (entry.isDirectory) + { + if (recursive) + entry = ScanDirectoryTree(physical_name, true); + else + entry.size = 0; + } + else + { + entry.size = GetSize(physical_name); + } + entry.virtualName = virtual_name; + entry.physicalName = physical_name; + + ++parent_entry.size; + // Push into the tree + parent_entry.children.push_back(entry); + #ifdef _WIN32 + } while (FindNextFile(hFind, &ffd) != 0); FindClose(hFind); #else } closedir(dirp); #endif // Return number of entries found. - return foundEntries; + return parent_entry; } diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index 2416c0ae6f..3ad7b08d5b 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -107,9 +107,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename); // creates an empty file filename, returns true on success bool CreateEmptyFile(const std::string &filename); -// Scans the directory tree gets, starting from _Directory and adds the -// results into parentEntry. Returns the number of files+directories found -u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry); +// Recursive or non-recursive list of files under directory. +FSTEntry ScanDirectoryTree(const std::string &directory, bool recursive); // deletes the given directory and anything under it. Returns true on success. bool DeleteDirRecursively(const std::string &directory); diff --git a/Source/Core/Core/HW/GCMemcardDirectory.cpp b/Source/Core/Core/HW/GCMemcardDirectory.cpp index 5b89e45926..f87fd3eede 100644 --- a/Source/Core/Core/HW/GCMemcardDirectory.cpp +++ b/Source/Core/Core/HW/GCMemcardDirectory.cpp @@ -151,16 +151,7 @@ GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u hdrfile.ReadBytes(&m_hdr, BLOCK_SIZE); } - File::FSTEntry FST_Temp; - File::ScanDirectoryTree(m_SaveDirectory, FST_Temp); - - CFileSearch::XStringVector Directory; - Directory.push_back(m_SaveDirectory); - CFileSearch::XStringVector Extensions; - Extensions.push_back("*.gci"); - - CFileSearch FileSearch(Extensions, Directory); - const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames(); + std::vector rFilenames = DoFileSearch({"*.gci"}, {m_SaveDirectory}); if (rFilenames.size() > 112) { @@ -170,7 +161,7 @@ GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u 4000); } - for (auto gciFile : rFilenames) + for (const std::string& gciFile : rFilenames) { if (m_saves.size() == DIRLEN) { diff --git a/Source/Core/Core/HW/WiiSaveCrypted.cpp b/Source/Core/Core/HW/WiiSaveCrypted.cpp index 08ad867872..4d50fcaa21 100644 --- a/Source/Core/Core/HW/WiiSaveCrypted.cpp +++ b/Source/Core/Core/HW/WiiSaveCrypted.cpp @@ -67,9 +67,8 @@ void CWiiSaveCrypted::ExportAllSaves() const u32 path_mask = 0x00010000; for (int i = 0; i < 8; ++i) { - File::FSTEntry fst_tmp; std::string folder = StringFromFormat("%s/%08x/", title_folder.c_str(), path_mask | i); - File::ScanDirectoryTree(folder, fst_tmp); + File::FSTEntry fst_tmp = File::ScanDirectoryTree(folder, false); for (const File::FSTEntry& entry : fst_tmp.children) { @@ -627,8 +626,7 @@ void CWiiSaveCrypted::ScanForFiles(const std::string& save_directory, std::vecto file_list.push_back(directories[i]); } - File::FSTEntry fst_tmp; - File::ScanDirectoryTree(directories[i], fst_tmp); + File::FSTEntry fst_tmp = File::ScanDirectoryTree(directories[i], false); for (const File::FSTEntry& elem : fst_tmp.children) { if (elem.virtualName != "banner.bin") diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp index 89ffb3c4b6..70368267f8 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp @@ -5,7 +5,6 @@ #include "Common/ChunkFile.h" #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" -#include "Common/FileSearch.h" #include "Common/FileUtil.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" @@ -106,25 +105,28 @@ IPCCommandResult CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress) break; } - // make a file search - CFileSearch::XStringVector Directories; - Directories.push_back(DirName); - - CFileSearch::XStringVector Extensions; - Extensions.push_back("*.*"); - - CFileSearch FileSearch(Extensions, Directories); + File::FSTEntry entry = File::ScanDirectoryTree(DirName, false); // it is one if ((CommandBuffer.InBuffer.size() == 1) && (CommandBuffer.PayloadBuffer.size() == 1)) { - size_t numFile = FileSearch.GetFileNames().size(); + size_t numFile = entry.children.size(); INFO_LOG(WII_IPC_FILEIO, "\t%lu files found", (unsigned long)numFile); Memory::Write_U32((u32)numFile, CommandBuffer.PayloadBuffer[0].m_Address); } else { + for (File::FSTEntry& child : entry.children) + { + // Decode entities of invalid file system characters so that + // games (such as HP:HBP) will be able to find what they expect. + for (const Common::replace_t& r : replacements) + child.virtualName = ReplaceAll(child.virtualName, r.second, {r.first}); + } + + std::sort(entry.children.begin(), entry.children.end(), [](const File::FSTEntry& one, const File::FSTEntry& two) { return one.virtualName < two.virtualName; }); + u32 MaxEntries = Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address); memset(Memory::GetPointer(CommandBuffer.PayloadBuffer[0].m_Address), 0, CommandBuffer.PayloadBuffer[0].m_Size); @@ -132,22 +134,10 @@ IPCCommandResult CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress) size_t numFiles = 0; char* pFilename = (char*)Memory::GetPointer((u32)(CommandBuffer.PayloadBuffer[0].m_Address)); - for (size_t i=0; i= MaxEntries) - break; + const std::string& FileName = entry.children[i].virtualName; - std::string name, ext; - SplitPath(FileSearch.GetFileNames()[i], nullptr, &name, &ext); - std::string FileName = name + ext; - - // Decode entities of invalid file system characters so that - // games (such as HP:HBP) will be able to find what they expect. - for (const Common::replace_t& r : replacements) - { - for (size_t j = 0; (j = FileName.find(r.second, j)) != FileName.npos; ++j) - FileName.replace(j, r.second.length(), 1, r.first); - } strcpy(pFilename, FileName.c_str()); pFilename += FileName.length(); @@ -192,10 +182,9 @@ IPCCommandResult CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress) } else { - File::FSTEntry parentDir; - // add one for the folder itself, allows some games to create their save files - // R8XE52 (Jurassic: The Hunted), STEETR (Tetris Party Deluxe) now create their saves with this change - iNodes = 1 + File::ScanDirectoryTree(path, parentDir); + File::FSTEntry parentDir = File::ScanDirectoryTree(path, true); + // add one for the folder itself + iNodes = 1 + (u32)parentDir.size; u64 totalSize = ComputeTotalFileSize(parentDir); // "Real" size, to be converted to nand blocks @@ -542,8 +531,7 @@ void CWII_IPC_HLE_Device_fs::DoState(PointerWrap& p) { //recurse through tmp and save dirs and files - File::FSTEntry parentEntry; - File::ScanDirectoryTree(Path, parentEntry); + File::FSTEntry parentEntry = File::ScanDirectoryTree(Path, true); std::deque todo; todo.insert(todo.end(), parentEntry.children.begin(), parentEntry.children.end()); diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index fb60dd1535..b7fe30aed5 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -339,7 +339,7 @@ void CVolumeDirectory::BuildFST() File::FSTEntry rootEntry; // read data from physical disk to rootEntry - u32 totalEntries = AddDirectoryEntries(m_rootDirectory, rootEntry) + 1; + u64 totalEntries = AddDirectoryEntries(m_rootDirectory, rootEntry) + 1; m_fstNameOffset = totalEntries * ENTRY_SIZE; // offset in FST nameTable m_FSTData.resize(m_fstNameOffset + m_totalNameSize); @@ -423,7 +423,7 @@ void CVolumeDirectory::Write32(u32 data, u32 offset, std::vector* const buff (*buffer)[offset] = (data) & 0xff; } -void CVolumeDirectory::WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u32 length) +void CVolumeDirectory::WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u64 length) { m_FSTData[entryOffset++] = type; @@ -451,7 +451,7 @@ void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u { u32 myOffset = fstOffset; u32 myEntryNum = myOffset / ENTRY_SIZE; - WriteEntryData(fstOffset, DIRECTORY_ENTRY, nameOffset, parentEntryNum, (u32)(myEntryNum + entry.size + 1)); + WriteEntryData(fstOffset, DIRECTORY_ENTRY, nameOffset, parentEntryNum, myEntryNum + entry.size + 1); WriteEntryName(nameOffset, entry.virtualName); for (const auto& child : entry.children) @@ -462,7 +462,7 @@ void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u else { // put entry in FST - WriteEntryData(fstOffset, FILE_ENTRY, nameOffset, dataOffset, (u32)entry.size); + WriteEntryData(fstOffset, FILE_ENTRY, nameOffset, dataOffset, entry.size); WriteEntryName(nameOffset, entry.virtualName); // write entry to virtual disk @@ -490,11 +490,11 @@ static u32 ComputeNameSize(const File::FSTEntry& parentEntry) return nameSize; } -u32 CVolumeDirectory::AddDirectoryEntries(const std::string& _Directory, File::FSTEntry& parentEntry) +u64 CVolumeDirectory::AddDirectoryEntries(const std::string& _Directory, File::FSTEntry& parentEntry) { - u32 foundEntries = ScanDirectoryTree(_Directory, parentEntry); + parentEntry = File::ScanDirectoryTree(_Directory, true); m_totalNameSize += ComputeNameSize(parentEntry); - return foundEntries; + return parentEntry.size; } } // namespace diff --git a/Source/Core/DiscIO/VolumeDirectory.h b/Source/Core/DiscIO/VolumeDirectory.h index 893e10e08c..9ac3be7a89 100644 --- a/Source/Core/DiscIO/VolumeDirectory.h +++ b/Source/Core/DiscIO/VolumeDirectory.h @@ -75,12 +75,12 @@ private: void Write32(u32 data, u32 offset, std::vector* const buffer); // FST creation - void WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u32 length); + void WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u64 length); void WriteEntryName(u32& nameOffset, const std::string& name); void WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u32& nameOffset, u64& dataOffset, u32 parentEntryNum); // returns number of entries found in _Directory - u32 AddDirectoryEntries(const std::string& _Directory, File::FSTEntry& parentEntry); + u64 AddDirectoryEntries(const std::string& _Directory, File::FSTEntry& parentEntry); std::string m_rootDirectory; diff --git a/Source/Core/DolphinQt/GameList/GameTracker.cpp b/Source/Core/DolphinQt/GameList/GameTracker.cpp index 4673abf8ee..8bb41c39aa 100644 --- a/Source/Core/DolphinQt/GameList/GameTracker.cpp +++ b/Source/Core/DolphinQt/GameList/GameTracker.cpp @@ -25,9 +25,9 @@ void AbstractGameList::RemoveGames(QList items) DGameTracker::DGameTracker(QWidget* parent_widget) : QStackedWidget(parent_widget), - m_watcher(this) + m_watcher(new QFileSystemWatcher(this)) { - connect(&m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(ScanForGames())); + connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(ScanForGames())); m_tree_widget = new DGameTree(this); addWidget(m_tree_widget); @@ -78,38 +78,20 @@ void DGameTracker::ScanForGames() { setDisabled(true); - CFileSearch::XStringVector dirs(SConfig::GetInstance().m_ISOFolder); - + delete m_watcher; + m_watcher = new QFileSystemWatcher(this); if (SConfig::GetInstance().m_RecursiveISOFolder) { - for (u32 i = 0; i < dirs.size(); i++) - { - File::FSTEntry FST_Temp; - File::ScanDirectoryTree(dirs[i], FST_Temp); - for (auto& entry : FST_Temp.children) - { - if (entry.isDirectory) - { - bool duplicate = false; - for (auto& dir : dirs) - { - if (dir == entry.physicalName) - { - duplicate = true; - break; - } - } - if (!duplicate) - dirs.push_back(entry.physicalName); - } - } - } + for (std::string dir : FindSubdirectories(SConfig::GetInstance().m_ISOFolder, /*recursive*/ true)) + m_watcher->addPath(QString::fromStdString(dir)); + } + else + { + for (std::string dir : SConfig::GetInstance().m_ISOFolder) + m_watcher->addPath(QString::fromStdString(dir)); } - for (std::string& dir : dirs) - m_watcher.addPath(QString::fromStdString(dir)); - - CFileSearch::XStringVector exts; + std::vector exts; if (SConfig::GetInstance().m_ListGC) { exts.push_back("*.gcm"); @@ -124,8 +106,7 @@ void DGameTracker::ScanForGames() if (SConfig::GetInstance().m_ListWad) exts.push_back("*.wad"); - CFileSearch FileSearch(exts, dirs); - const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames(); + auto rFilenames = DoFileSearch(exts, SConfig::GetInstance().m_ISOFolder, SConfig::GetInstance().m_RecursiveISOFolder); QList newItems; QStringList allItems; diff --git a/Source/Core/DolphinQt/GameList/GameTracker.h b/Source/Core/DolphinQt/GameList/GameTracker.h index d51cdd20bf..7501874613 100644 --- a/Source/Core/DolphinQt/GameList/GameTracker.h +++ b/Source/Core/DolphinQt/GameList/GameTracker.h @@ -60,7 +60,7 @@ public slots: private: QMap m_games; - QFileSystemWatcher m_watcher; + QFileSystemWatcher* m_watcher; GameListStyle m_current_style; DGameGrid* m_grid_widget = nullptr; diff --git a/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp b/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp index 935ea03fee..a57774a8cd 100644 --- a/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp @@ -162,12 +162,10 @@ void InterfaceConfigPane::LoadGUIValues() void InterfaceConfigPane::LoadThemes() { - CFileSearch::XStringVector theme_dirs; - theme_dirs.push_back(File::GetUserPath(D_THEMES_IDX)); - theme_dirs.push_back(File::GetSysDirectory() + THEMES_DIR); - - CFileSearch cfs(CFileSearch::XStringVector(1, "*"), theme_dirs); - auto const& sv = cfs.GetFileNames(); + auto sv = DoFileSearch({"*"}, { + File::GetUserPath(D_THEMES_IDX), + File::GetSysDirectory() + THEMES_DIR + }, /*recursive*/ false); for (const std::string& filename : sv) { std::string name, ext; diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 47aecfef4b..04e31fbfaf 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -1966,15 +1966,9 @@ void CFrame::GameListChanged(wxCommandEvent& event) SConfig::GetInstance().m_ListDrives = event.IsChecked(); break; case IDM_PURGE_CACHE: - CFileSearch::XStringVector Directories; - Directories.push_back(File::GetUserPath(D_CACHE_IDX)); - CFileSearch::XStringVector Extensions; - Extensions.push_back("*.cache"); + std::vector rFilenames = DoFileSearch({"*.cache"}, {File::GetUserPath(D_CACHE_IDX)}); - CFileSearch FileSearch(Extensions, Directories); - const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames(); - - for (auto& rFilename : rFilenames) + for (const std::string& rFilename : rFilenames) { File::Delete(rFilename); } diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index f0e8667a7a..afcadacaef 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -466,35 +466,7 @@ void CGameListCtrl::ScanForISOs() { ClearIsoFiles(); - CFileSearch::XStringVector Directories(SConfig::GetInstance().m_ISOFolder); - - if (SConfig::GetInstance().m_RecursiveISOFolder) - { - for (u32 i = 0; i < Directories.size(); i++) - { - File::FSTEntry FST_Temp; - File::ScanDirectoryTree(Directories[i], FST_Temp); - for (auto& Entry : FST_Temp.children) - { - if (Entry.isDirectory) - { - bool duplicate = false; - for (auto& Directory : Directories) - { - if (Directory == Entry.physicalName) - { - duplicate = true; - break; - } - } - if (!duplicate) - Directories.push_back(Entry.physicalName); - } - } - } - } - - CFileSearch::XStringVector Extensions; + std::vector Extensions; if (SConfig::GetInstance().m_ListGC) Extensions.push_back("*.gcm"); @@ -508,8 +480,7 @@ void CGameListCtrl::ScanForISOs() if (SConfig::GetInstance().m_ListWad) Extensions.push_back("*.wad"); - CFileSearch FileSearch(Extensions, Directories); - const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames(); + auto rFilenames = DoFileSearch(Extensions, SConfig::GetInstance().m_ISOFolder, SConfig::GetInstance().m_RecursiveISOFolder); if (rFilenames.size() > 0) { diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp index 54efaad3d2..4101dcdbf5 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.cpp +++ b/Source/Core/DolphinWX/InputConfigDiag.cpp @@ -172,18 +172,14 @@ void InputConfigDialog::UpdateProfileComboBox() pname += PROFILES_PATH; pname += m_config.profile_name; - CFileSearch::XStringVector exts; - exts.push_back("*.ini"); - CFileSearch::XStringVector dirs; - dirs.push_back(pname); - CFileSearch cfs(exts, dirs); - const CFileSearch::XStringVector& sv = cfs.GetFileNames(); + std::vector sv = DoFileSearch({"*.ini"}, {pname}); wxArrayString strs; - for (auto si = sv.cbegin(); si != sv.cend(); ++si) + for (const std::string& filename : sv) { - std::string str(si->begin() + si->find_last_of('/') + 1 , si->end() - 4) ; - strs.push_back(StrToWxStr(str)); + std::string base; + SplitPath(filename, nullptr, &base, nullptr); + strs.push_back(StrToWxStr(base)); } for (GamepadPage* page : m_padpages) diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index c1a8b59280..464064ebac 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -38,9 +38,11 @@ Make AA apply instantly during gameplay if possible #include #include +#include #include "Common/Atomic.h" #include "Common/CommonPaths.h" +#include "Common/FileSearch.h" #include "Common/Thread.h" #include "Common/Logging/LogManager.h" @@ -95,39 +97,16 @@ std::string VideoBackend::GetDisplayName() const return "OpenGL"; } -static void GetShaders(std::vector &shaders, const std::string &sub_dir = "") +static std::vector GetShaders(const std::string &sub_dir = "") { - std::set already_found; - - shaders.clear(); - const std::string directories[] = { + std::vector paths = DoFileSearch({"*.glsl"}, { File::GetUserPath(D_SHADERS_IDX) + sub_dir, - File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir, - }; - for (auto& directory : directories) - { - if (!File::IsDirectory(directory)) - continue; - - File::FSTEntry entry; - File::ScanDirectoryTree(directory, entry); - for (auto& file : entry.children) - { - std::string name = file.virtualName; - if (name.size() < 5) - continue; - if (strcasecmp(name.substr(name.size() - 5).c_str(), ".glsl")) - continue; - - name = name.substr(0, name.size() - 5); - if (already_found.find(name) != already_found.end()) - continue; - - already_found.insert(name); - shaders.push_back(name); - } - } - std::sort(shaders.begin(), shaders.end()); + File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + }); + std::vector result; + for (std::string path : paths) + result.push_back(std::regex_replace(path, std::regex("^.*/(.*)\\.glsl$"), "$1")); + return result; } static void InitBackendInfo() @@ -146,8 +125,8 @@ static void InitBackendInfo() g_Config.backend_info.AAModes.assign(caamodes, caamodes + sizeof(caamodes)/sizeof(*caamodes)); // pp shaders - GetShaders(g_Config.backend_info.PPShaders); - GetShaders(g_Config.backend_info.AnaglyphShaders, std::string(ANAGLYPH_DIR DIR_SEP)); + g_Config.backend_info.PPShaders = GetShaders(""); + g_Config.backend_info.AnaglyphShaders = GetShaders(ANAGLYPH_DIR DIR_SEP); } void VideoBackend::ShowConfig(void *_hParent) diff --git a/Source/Core/VideoCommon/HiresTextures.cpp b/Source/Core/VideoCommon/HiresTextures.cpp index ac764fcd4f..9c7e9f3084 100644 --- a/Source/Core/VideoCommon/HiresTextures.cpp +++ b/Source/Core/VideoCommon/HiresTextures.cpp @@ -79,38 +79,12 @@ void HiresTexture::Update() s_textureCache.clear(); } - CFileSearch::XStringVector Directories; + std::vector Directories; const std::string& gameCode = SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID; std::string szDir = StringFromFormat("%s%s", File::GetUserPath(D_HIRESTEXTURES_IDX).c_str(), gameCode.c_str()); - Directories.push_back(szDir); - for (u32 i = 0; i < Directories.size(); i++) - { - File::FSTEntry FST_Temp; - File::ScanDirectoryTree(Directories[i], FST_Temp); - for (auto& entry : FST_Temp.children) - { - if (entry.isDirectory) - { - bool duplicate = false; - - for (auto& Directory : Directories) - { - if (Directory == entry.physicalName) - { - duplicate = true; - break; - } - } - - if (!duplicate) - Directories.push_back(entry.physicalName); - } - } - } - - CFileSearch::XStringVector Extensions = { + std::vector Extensions { "*.png", "*.bmp", "*.tga", @@ -118,8 +92,7 @@ void HiresTexture::Update() "*.jpg" // Why not? Could be useful for large photo-like textures }; - CFileSearch FileSearch(Extensions, Directories); - const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames(); + auto rFilenames = DoFileSearch(Extensions, {szDir}, /*recursive*/ true); const std::string code = StringFromFormat("%s_", gameCode.c_str()); const std::string code2 = ""; @@ -129,13 +102,8 @@ void HiresTexture::Update() std::string FileName; SplitPath(rFilename, nullptr, &FileName, nullptr); - if (FileName.substr(0, code.length()) == code) - { - s_textureMap[FileName] = rFilename; - s_check_native_format = true; - } - - if (FileName.substr(0, s_format_prefix.length()) == s_format_prefix) + if (FileName.substr(0, code.length()) == code || + FileName.substr(0, s_format_prefix.length()) == s_format_prefix) { s_textureMap[FileName] = rFilename; s_check_new_format = true; From a0a80c9a9cc247024c012be474fb92d1c290d9b1 Mon Sep 17 00:00:00 2001 From: comex Date: Sun, 16 Nov 2014 13:54:41 -0500 Subject: [PATCH 2/9] Fix CopyDir to not require source and dest paths to end with "/". --- Source/Core/Common/FileUtil.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 980821e010..19269e88d3 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -627,14 +627,11 @@ void CopyDir(const std::string &source_path, const std::string &dest_path) if (virtualName == "." || virtualName == "..") continue; - std::string source, dest; - source = source_path + virtualName; - dest = dest_path + virtualName; + std::string source = source_path + DIR_SEP + virtualName; + std::string dest = dest_path + DIR_SEP + virtualName; if (IsDirectory(source)) { - source += '/'; - dest += '/'; - if (!File::Exists(dest)) File::CreateFullPath(dest); + if (!File::Exists(dest)) File::CreateFullPath(dest + DIR_SEP); CopyDir(source, dest); } else if (!File::Exists(dest)) File::Copy(source, dest); From aae104ccb4950c821be08a46314157a8e04580d7 Mon Sep 17 00:00:00 2001 From: comex Date: Sat, 15 Nov 2014 16:42:15 -0500 Subject: [PATCH 3/9] Disable some stuff in IPC_HLE when determinism is required. This includes net, which is nonsensical to "sync" in netplay/replays (could have the host do the Wii networking in future though...), and USB keyboard, which just needs some love to do the same. --- .../Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp | 5 +++++ Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h | 14 ++++++++++---- .../Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp | 9 +++++++++ .../Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp | 6 ++++-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp index d94afd8d10..d52c4b7b9e 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp @@ -15,6 +15,7 @@ #include "Common/StringUtil.h" #include "Core/ConfigManager.h" +#include "Core/Core.h" #include "Core/ec_wii.h" #include "Core/IPC_HLE/ICMP.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h" @@ -314,6 +315,10 @@ static void GetMacAddress(u8* mac) // Parse MAC address from config, and generate a new one if it doesn't // exist or can't be parsed. std::string wireless_mac = SConfig::GetInstance().m_WirelessMac; + + if (Core::g_want_determinism) + wireless_mac = "12:34:56:78:9a:bc"; + if (!StringToMacAddress(wireless_mac, mac)) { GenerateMacAddress(IOS, mac); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h index 6c32ab0067..b06b45f7d0 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h @@ -7,6 +7,7 @@ #include "Common/FileUtil.h" #include "Common/Timer.h" +#include "Core/HW/EXI_DeviceIPL.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" #ifdef _WIN32 @@ -528,21 +529,26 @@ private: u64 rtc; s64 utcdiff; - // Seconds between 1.1.1970 and 4.1.2008 16:00:38 - static const u64 wii_bias = 0x477E5826; + // TODO: depending on CEXIIPL is a hack which I don't feel like removing + // because the function itself is pretty hackish; wait until I re-port my + // netplay rewrite; also, is that random 16:00:38 actually meaningful? + // seems very very doubtful since Wii was released in 2006 + + // Seconds between 1.1.2000 and 4.1.2008 16:00:38 + static const u64 wii_bias = 0x477E5826 - 0x386D4380; // Returns seconds since Wii epoch // +/- any bias set from IOCTL_NW24_SET_UNIVERSAL_TIME u64 GetAdjustedUTC() const { - return Common::Timer::GetTimeSinceJan1970() - wii_bias + utcdiff; + return CEXIIPL::GetGCTime() - wii_bias + utcdiff; } // Store the difference between what the Wii thinks is UTC and // what the host OS thinks void SetAdjustedUTC(u64 wii_utc) { - utcdiff = Common::Timer::GetTimeSinceJan1970() - wii_bias - wii_utc; + utcdiff = CEXIIPL::GetGCTime() - wii_bias - wii_utc; } }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp index 7feb29fdc7..456e181960 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp @@ -5,6 +5,7 @@ #include #include "Common/FileUtil.h" +#include "Core/Core.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h" #include "Core/IPC_HLE/WII_Socket.h" @@ -127,6 +128,14 @@ IPCCommandResult CWII_IPC_HLE_Device_net_ssl::IOCtlV(u32 _CommandAddress) BufferOutSize3 = CommandBuffer.PayloadBuffer.at(2).m_Size; } + // I don't trust SSL to be deterministic, and this is never going to sync + // as such (as opposed to forwarding IPC results or whatever), so - + if (Core::g_want_determinism) + { + Memory::Write_U32(-1, _CommandAddress + 0x4); + return IPC_DEFAULT_REPLY; + } + switch (CommandBuffer.Parameter) { case IOCTLV_NET_SSL_NEW: diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp index ccc292dc93..de029d33bd 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp @@ -13,6 +13,8 @@ #include #endif +// TODO: support in netplay/movies. + CWII_IPC_HLE_Device_usb_kbd::CWII_IPC_HLE_Device_usb_kbd(u32 _DeviceID, const std::string& _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) {} @@ -64,7 +66,7 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_kbd::IOCtl(u32 _CommandAddress) { u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - if (SConfig::GetInstance().m_WiiKeyboard && !m_MessageQueue.empty()) + if (SConfig::GetInstance().m_WiiKeyboard && !Core::g_want_determinism && !m_MessageQueue.empty()) { Memory::CopyToEmu(BufferOut, &m_MessageQueue.front(), sizeof(SMessageData)); m_MessageQueue.pop(); @@ -89,7 +91,7 @@ bool CWII_IPC_HLE_Device_usb_kbd::IsKeyPressed(int _Key) u32 CWII_IPC_HLE_Device_usb_kbd::Update() { - if (!SConfig::GetInstance().m_WiiKeyboard || !m_Active) + if (!SConfig::GetInstance().m_WiiKeyboard || Core::g_want_determinism || !m_Active) return 0; u8 Modifiers = 0x00; From 3173d4dcbfc112eebba81e1e18372f7385c7adc3 Mon Sep 17 00:00:00 2001 From: comex Date: Sat, 15 Nov 2014 23:04:09 -0500 Subject: [PATCH 4/9] Disable /dev/usb/hid too. --- Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp index 515f11d95a..3cd76a9356 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp @@ -129,6 +129,12 @@ IPCCommandResult CWII_IPC_HLE_Device_hid::Close(u32 _CommandAddress, bool _bForc IPCCommandResult CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) { + if (Core::g_want_determinism) + { + Memory::Write_U32(-1, _CommandAddress + 0x4); + return IPC_DEFAULT_REPLY; + } + u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); From f6c6822f71e795563e5eacdb28c2a740ca79b520 Mon Sep 17 00:00:00 2001 From: comex Date: Mon, 17 Nov 2014 13:40:59 -0500 Subject: [PATCH 5/9] The old g_want_determinism check in WiiSockMan missed a few cases. Move to net.cpp. Specifically, things like GETHOSTBYNAME, GETHOSTID, etc. could be done without creating a socket, which is what the old check blocked. Now we check at the ioctl and ioctlv handlers. Might be possible to get a bit more realistic behavior in future by filtering individual ioctls, but it probably doesn't matter. --- .../Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp | 114 ++++++++++-------- Source/Core/Core/IPC_HLE/WII_Socket.cpp | 5 - 2 files changed, 62 insertions(+), 57 deletions(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp index d52c4b7b9e..69cf92c1ed 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp @@ -644,6 +644,13 @@ static unsigned int opt_name_mapping[][2] = { IPCCommandResult CWII_IPC_HLE_Device_net_ip_top::IOCtl(u32 _CommandAddress) { + if (Core::g_want_determinism) + { + Memory::Write_U32(-1, _CommandAddress + 4); + return IPC_DEFAULT_REPLY; + } + + u32 Command = Memory::Read_U32(_CommandAddress + 0x0C); u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); @@ -1222,65 +1229,68 @@ IPCCommandResult CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) { u32 address = 0; #ifdef _WIN32 - PIP_ADAPTER_ADDRESSES AdapterAddresses = nullptr; - ULONG OutBufferLength = 0; - ULONG RetVal = 0, i; - for (i = 0; i < 5; ++i) + if (!Core::g_want_determinism) { - RetVal = GetAdaptersAddresses( - AF_INET, - 0, - nullptr, - AdapterAddresses, - &OutBufferLength); - - if (RetVal != ERROR_BUFFER_OVERFLOW) + PIP_ADAPTER_ADDRESSES AdapterAddresses = nullptr; + ULONG OutBufferLength = 0; + ULONG RetVal = 0, i; + for (i = 0; i < 5; ++i) { - break; - } + RetVal = GetAdaptersAddresses( + AF_INET, + 0, + nullptr, + AdapterAddresses, + &OutBufferLength); + if (RetVal != ERROR_BUFFER_OVERFLOW) + { + break; + } + + if (AdapterAddresses != nullptr) + { + FREE(AdapterAddresses); + } + + AdapterAddresses = (PIP_ADAPTER_ADDRESSES)MALLOC(OutBufferLength); + if (AdapterAddresses == nullptr) + { + RetVal = GetLastError(); + break; + } + } + if (RetVal == NO_ERROR) + { + unsigned long dwBestIfIndex = 0; + IPAddr dwDestAddr = (IPAddr)0x08080808; + // If successful, output some information from the data we received + PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses; + if (GetBestInterface(dwDestAddr, &dwBestIfIndex) == NO_ERROR) + { + while (AdapterList) + { + if (AdapterList->IfIndex == dwBestIfIndex && + AdapterList->FirstDnsServerAddress && + AdapterList->OperStatus == IfOperStatusUp) + { + INFO_LOG(WII_IPC_NET, "Name of valid interface: %S", AdapterList->FriendlyName); + INFO_LOG(WII_IPC_NET, "DNS: %u.%u.%u.%u", + (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2], + (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[3], + (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[4], + (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[5]); + address = Common::swap32(*(u32*)(&AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2])); + break; + } + AdapterList = AdapterList->Next; + } + } + } if (AdapterAddresses != nullptr) { FREE(AdapterAddresses); } - - AdapterAddresses = (PIP_ADAPTER_ADDRESSES)MALLOC(OutBufferLength); - if (AdapterAddresses == nullptr) - { - RetVal = GetLastError(); - break; - } - } - if (RetVal == NO_ERROR) - { - unsigned long dwBestIfIndex = 0; - IPAddr dwDestAddr = (IPAddr)0x08080808; - // If successful, output some information from the data we received - PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses; - if (GetBestInterface(dwDestAddr, &dwBestIfIndex) == NO_ERROR) - { - while (AdapterList) - { - if (AdapterList->IfIndex == dwBestIfIndex && - AdapterList->FirstDnsServerAddress && - AdapterList->OperStatus == IfOperStatusUp) - { - INFO_LOG(WII_IPC_NET, "Name of valid interface: %S", AdapterList->FriendlyName); - INFO_LOG(WII_IPC_NET, "DNS: %u.%u.%u.%u", - (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2], - (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[3], - (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[4], - (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[5]); - address = Common::swap32(*(u32*)(&AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2])); - break; - } - AdapterList = AdapterList->Next; - } - } - } - if (AdapterAddresses != nullptr) - { - FREE(AdapterAddresses); } #endif if (address == 0) diff --git a/Source/Core/Core/IPC_HLE/WII_Socket.cpp b/Source/Core/Core/IPC_HLE/WII_Socket.cpp index ca8f457738..8799c84d29 100644 --- a/Source/Core/Core/IPC_HLE/WII_Socket.cpp +++ b/Source/Core/Core/IPC_HLE/WII_Socket.cpp @@ -562,11 +562,6 @@ void WiiSockMan::AddSocket(s32 fd) s32 WiiSockMan::NewSocket(s32 af, s32 type, s32 protocol) { - if (Core::g_want_determinism) - { - return SO_ENOMEM; - } - s32 fd = (s32)socket(af, type, protocol); s32 ret = GetNetErrorCode(fd, "NewSocket", false); AddSocket(ret); From dc91e8b60793276e83cc3c141dcdc551aa36d8ed Mon Sep 17 00:00:00 2001 From: comex Date: Mon, 17 Nov 2014 20:59:14 -0500 Subject: [PATCH 6/9] Add a mode to use a dummy Wii NAND. Eventually, netplay will be able to use the host's NAND, but this could still be useful in some cases; for TAS it definitely makes sense to have a way to avoid using any preexisting NAND. In terms of implementation: remove D_WIIUSER_IDX, which was just WIIROOT + "/", as well as some other indices which are pointless to have as separate variables rather than just using the actual path (fixed, since they're actual Wii NAND paths) at the call site. Then split off D_SESSION_WIIROOT_IDX, which can point to the dummy NAND directory, from D_WIIROOT_IDX, which always points to the "real" one the user configured. --- Source/Core/Common/FileUtil.cpp | 38 +++++++++---- Source/Core/Common/FileUtil.h | 10 ++-- Source/Core/Common/NandPaths.cpp | 54 ++++++++++++++++--- Source/Core/Common/NandPaths.h | 3 ++ Source/Core/Common/SysConf.cpp | 9 ++-- Source/Core/Core/ConfigManager.cpp | 2 - Source/Core/Core/Core.cpp | 1 + Source/Core/Core/HW/HW.cpp | 6 +++ Source/Core/Core/HW/WiiSaveCrypted.cpp | 2 +- .../Core/HW/WiimoteEmu/EmuSubroutines.cpp | 5 +- .../IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp | 5 +- .../Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp | 5 +- .../Core/IPC_HLE/WII_IPC_HLE_Device_net.h | 10 ++-- .../IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp | 6 +-- .../IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp | 2 +- Source/Core/Core/ec_wii.cpp | 2 +- Source/Core/DiscIO/NANDContentLoader.cpp | 8 +-- Source/Core/DiscIO/VolumeCommon.cpp | 4 +- Source/Core/DolphinQt/GameList/GameFile.cpp | 2 +- .../Core/DolphinWX/Config/PathConfigPane.cpp | 2 - Source/Core/DolphinWX/ISOFile.cpp | 4 +- Source/Core/DolphinWX/MainAndroid.cpp | 2 +- Source/Core/UICommon/UICommon.cpp | 4 +- 23 files changed, 127 insertions(+), 59 deletions(-) diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 19269e88d3..925e3f1ed3 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -20,6 +20,7 @@ #include // for GetSaveFileName #include // getcwd #include +#include // guid stuff #include #include #else @@ -666,6 +667,32 @@ bool SetCurrentDir(const std::string &directory) return __chdir(directory.c_str()) == 0; } +std::string CreateTempDir() +{ +#ifdef _WIN32 + TCHAR temp[MAX_PATH]; + if (!GetTempPath(MAX_PATH, temp)) + return ""; + + GUID guid; + CoCreateGuid(&guid); + TCHAR tguid[40]; + StringFromGUID2(guid, tguid, 39); + tguid[39] = 0; + std::string dir = TStrToUTF8(temp) + "/" + TStrToUTF8(tguid); + if (!CreateDir(dir)) + return ""; + dir = ReplaceAll(dir, "\\", DIR_SEP); + return dir; +#else + const char* base = getenv("TMPDIR") ?: "/tmp"; + std::string path = std::string(base) + "/DolphinWii.XXXXXX"; + if (!mkdtemp(&path[0])) + return ""; + return path; +#endif +} + std::string GetTempFilenameForAtomicWrite(const std::string &path) { std::string abs = path; @@ -734,17 +761,9 @@ static void RebuildUserDirectories(unsigned int dir_index) { switch (dir_index) { - case D_WIIROOT_IDX: - s_user_paths[D_WIIUSER_IDX] = s_user_paths[D_WIIROOT_IDX] + DIR_SEP; - s_user_paths[D_WIISYSCONF_IDX] = s_user_paths[D_WIIUSER_IDX] + WII_SYSCONF_DIR + DIR_SEP; - s_user_paths[D_WIIWC24_IDX] = s_user_paths[D_WIIUSER_IDX] + WII_WC24CONF_DIR DIR_SEP; - s_user_paths[F_WIISYSCONF_IDX] = s_user_paths[D_WIISYSCONF_IDX] + WII_SYSCONF; - break; - case D_USER_IDX: s_user_paths[D_GCUSER_IDX] = s_user_paths[D_USER_IDX] + GC_USER_DIR DIR_SEP; s_user_paths[D_WIIROOT_IDX] = s_user_paths[D_USER_IDX] + WII_USER_DIR; - s_user_paths[D_WIIUSER_IDX] = s_user_paths[D_WIIROOT_IDX] + DIR_SEP; s_user_paths[D_CONFIG_IDX] = s_user_paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; s_user_paths[D_GAMESETTINGS_IDX] = s_user_paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP; s_user_paths[D_MAPS_IDX] = s_user_paths[D_USER_IDX] + MAPS_DIR DIR_SEP; @@ -762,14 +781,11 @@ static void RebuildUserDirectories(unsigned int dir_index) s_user_paths[D_DUMPDSP_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP; s_user_paths[D_LOGS_IDX] = s_user_paths[D_USER_IDX] + LOGS_DIR DIR_SEP; s_user_paths[D_MAILLOGS_IDX] = s_user_paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP; - s_user_paths[D_WIISYSCONF_IDX] = s_user_paths[D_WIIUSER_IDX] + WII_SYSCONF_DIR DIR_SEP; - s_user_paths[D_WIIWC24_IDX] = s_user_paths[D_WIIUSER_IDX] + WII_WC24CONF_DIR DIR_SEP; s_user_paths[D_THEMES_IDX] = s_user_paths[D_USER_IDX] + THEMES_DIR DIR_SEP; s_user_paths[F_DOLPHINCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DOLPHIN_CONFIG; s_user_paths[F_DEBUGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; s_user_paths[F_LOGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + LOGGER_CONFIG; s_user_paths[F_MAINLOG_IDX] = s_user_paths[D_LOGS_IDX] + MAIN_LOG; - s_user_paths[F_WIISYSCONF_IDX] = s_user_paths[D_WIISYSCONF_IDX] + WII_SYSCONF; s_user_paths[F_RAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + RAM_DUMP; s_user_paths[F_ARAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + ARAM_DUMP; s_user_paths[F_FAKEVMEMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + FAKEVMEM_DUMP; diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index 3ad7b08d5b..1337ee1670 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -20,8 +20,8 @@ enum { D_USER_IDX, D_GCUSER_IDX, - D_WIIROOT_IDX, - D_WIIUSER_IDX, + D_WIIROOT_IDX, // always points to User/Wii or global user-configured directory + D_SESSION_WIIROOT_IDX, // may point to minimal temporary directory for determinism D_CONFIG_IDX, // global settings D_GAMESETTINGS_IDX, // user-specified settings which override both the global and the default settings (per game) D_MAPS_IDX, @@ -39,14 +39,11 @@ enum { D_LOAD_IDX, D_LOGS_IDX, D_MAILLOGS_IDX, - D_WIISYSCONF_IDX, - D_WIIWC24_IDX, D_THEMES_IDX, F_DOLPHINCONFIG_IDX, F_DEBUGGERCONFIG_IDX, F_LOGGERCONFIG_IDX, F_MAINLOG_IDX, - F_WIISYSCONF_IDX, F_RAMDUMP_IDX, F_ARAMDUMP_IDX, F_FAKEVMEMDUMP_IDX, @@ -122,6 +119,9 @@ void CopyDir(const std::string &source_path, const std::string &dest_path); // Set the current directory to given directory bool SetCurrentDir(const std::string &directory); +// Creates and returns the path to a new temporary directory. +std::string CreateTempDir(); + // Get a filename that can hopefully be atomically renamed to the given path. std::string GetTempFilenameForAtomicWrite(const std::string &path); diff --git a/Source/Core/Common/NandPaths.cpp b/Source/Core/Common/NandPaths.cpp index c695d0744a..6037137410 100644 --- a/Source/Core/Common/NandPaths.cpp +++ b/Source/Core/Common/NandPaths.cpp @@ -7,6 +7,7 @@ #include #include +#include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/NandPaths.h" @@ -15,17 +16,55 @@ namespace Common { +static std::string s_temp_wii_root; + +void InitializeWiiRoot(bool use_dummy) +{ + ShutdownWiiRoot(); + if (use_dummy) + { + s_temp_wii_root = File::CreateTempDir(); + if (s_temp_wii_root.empty()) + { + ERROR_LOG(WII_IPC_FILEIO, "Could not create temporary directory"); + return; + } + File::CopyDir(File::GetSysDirectory() + WII_USER_DIR, s_temp_wii_root); + WARN_LOG(WII_IPC_FILEIO, "Using temporary directory %s for minimal Wii FS", s_temp_wii_root.c_str()); + static bool s_registered; + if (!s_registered) + { + s_registered = true; + atexit(ShutdownWiiRoot); + } + File::SetUserPath(D_SESSION_WIIROOT_IDX, s_temp_wii_root); + } + else + { + File::SetUserPath(D_SESSION_WIIROOT_IDX, File::GetUserPath(D_WIIROOT_IDX)); + } +} + +void ShutdownWiiRoot() +{ + if (!s_temp_wii_root.empty()) + { + File::DeleteDirRecursively(s_temp_wii_root); + s_temp_wii_root.clear(); + } +} + std::string GetTicketFileName(u64 _titleID) { - return StringFromFormat("%sticket/%08x/%08x.tik", - File::GetUserPath(D_WIIUSER_IDX).c_str(), + return StringFromFormat("%s/ticket/%08x/%08x.tik", + File::GetUserPath(D_SESSION_WIIROOT_IDX).c_str(), (u32)(_titleID >> 32), (u32)_titleID); } std::string GetTitleDataPath(u64 _titleID) { - return StringFromFormat("%stitle/%08x/%08x/data/", - File::GetUserPath(D_WIIUSER_IDX).c_str(), + return StringFromFormat("%s/title/%08x/%08x/data/", + File::GetUserPath(D_SESSION_WIIROOT_IDX).c_str(), (u32)(_titleID >> 32), (u32)_titleID); } @@ -35,8 +74,8 @@ std::string GetTMDFileName(u64 _titleID) } std::string GetTitleContentPath(u64 _titleID) { - return StringFromFormat("%stitle/%08x/%08x/content/", - File::GetUserPath(D_WIIUSER_IDX).c_str(), + return StringFromFormat("%s/title/%08x/%08x/content/", + File::GetUserPath(D_SESSION_WIIROOT_IDX).c_str(), (u32)(_titleID >> 32), (u32)_titleID); } @@ -89,8 +128,7 @@ void ReadReplacements(replace_v& replacements) { replacements.clear(); const std::string replace_fname = "/sys/replace"; - std::string filename(File::GetUserPath(D_WIIROOT_IDX)); - filename += replace_fname; + std::string filename = File::GetUserPath(D_SESSION_WIIROOT_IDX) + replace_fname; if (!File::Exists(filename)) CreateReplacementFile(filename); diff --git a/Source/Core/Common/NandPaths.h b/Source/Core/Common/NandPaths.h index 4adfed131f..6a79abf3bf 100644 --- a/Source/Core/Common/NandPaths.h +++ b/Source/Core/Common/NandPaths.h @@ -18,6 +18,9 @@ namespace Common typedef std::pair replace_t; typedef std::vector replace_v; + void InitializeWiiRoot(bool use_temporary); + void ShutdownWiiRoot(); + std::string GetTicketFileName(u64 _titleID); std::string GetTMDFileName(u64 _titleID); std::string GetTitleDataPath(u64 _titleID); diff --git a/Source/Core/Common/SysConf.cpp b/Source/Core/Common/SysConf.cpp index 94124c4957..a0d3aa1f04 100644 --- a/Source/Core/Common/SysConf.cpp +++ b/Source/Core/Common/SysConf.cpp @@ -8,6 +8,7 @@ #include #include +#include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/SysConf.h" @@ -15,8 +16,7 @@ SysConf::SysConf() : m_IsValid(false) { - m_FilenameDefault = File::GetUserPath(F_WIISYSCONF_IDX); - m_IsValid = LoadFromFile(m_FilenameDefault); + UpdateLocation(); } SysConf::~SysConf() @@ -409,7 +409,10 @@ void SysConf::UpdateLocation() // Clear the old filename and set the default filename to the new user path // So that it can be generated if the file does not exist in the new location m_Filename.clear(); - m_FilenameDefault = File::GetUserPath(F_WIISYSCONF_IDX); + // Note: We don't use the dummy Wii root here (if in use) because this is + // all tied up with the configuration code. In the future this should + // probably just be synced with the other settings. + m_FilenameDefault = File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF; Reload(); } diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index a06cc48839..81a85c5063 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -475,8 +475,6 @@ void SConfig::LoadGeneralSettings(IniFile& ini) general->Get("NANDRootPath", &m_NANDPath); File::SetUserPath(D_WIIROOT_IDX, m_NANDPath); - DiscIO::cUIDsys::AccessInstance().UpdateLocation(); - DiscIO::CSharedContent::AccessInstance().UpdateLocation(); general->Get("WirelessMac", &m_WirelessMac); } diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 2972760d34..449682e051 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -832,6 +832,7 @@ void UpdateWantDeterminism(bool initial) g_video_backend->UpdateWantDeterminism(new_want_determinism); // We need to clear the cache because some parts of the JIT depend on want_determinism, e.g. use of FMA. JitInterface::ClearCache(); + Common::InitializeWiiRoot(g_want_determinism); Core::PauseAndLock(false, was_unpaused); } diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index ef0aee3a85..533c392cf5 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -4,6 +4,7 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" +#include "Common/NandPaths.h" #include "Core/ConfigManager.h" #include "Core/Core.h" @@ -25,6 +26,7 @@ #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCAnalyst.h" +#include "DiscIO/NANDContentLoader.h" namespace HW { @@ -50,6 +52,9 @@ namespace HW if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) { + Common::InitializeWiiRoot(Core::g_want_determinism); + DiscIO::cUIDsys::AccessInstance().UpdateLocation(); + DiscIO::CSharedContent::AccessInstance().UpdateLocation(); WII_IPCInterface::Init(); WII_IPC_HLE_Interface::Init(); } @@ -70,6 +75,7 @@ namespace HW { WII_IPCInterface::Shutdown(); WII_IPC_HLE_Interface::Shutdown(); + Common::ShutdownWiiRoot(); } State::Shutdown(); diff --git a/Source/Core/Core/HW/WiiSaveCrypted.cpp b/Source/Core/Core/HW/WiiSaveCrypted.cpp index 4d50fcaa21..beae07402d 100644 --- a/Source/Core/Core/HW/WiiSaveCrypted.cpp +++ b/Source/Core/Core/HW/WiiSaveCrypted.cpp @@ -62,7 +62,7 @@ bool CWiiSaveCrypted::ExportWiiSave(u64 title_id) void CWiiSaveCrypted::ExportAllSaves() { - std::string title_folder = File::GetUserPath(D_WIIUSER_IDX) + "title"; + std::string title_folder = File::GetUserPath(D_WIIROOT_IDX) + "/title"; std::vector titles; const u32 path_mask = 0x00010000; for (int i = 0; i < 8; ++i) diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index feaa0c82b0..d075d8a192 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -22,6 +22,7 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" +#include "Common/NandPaths.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/WiimoteHid.h" @@ -275,7 +276,7 @@ void Wiimote::WriteData(const wm_write_data* const wd) { // writing the whole mii block each write :/ std::ofstream file; - OpenFStream(file, File::GetUserPath(D_WIIUSER_IDX) + "mii.bin", std::ios::binary | std::ios::out); + OpenFStream(file, File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin", std::ios::binary | std::ios::out); file.write((char*)m_eeprom + 0x0FCA, 0x02f0); file.close(); } @@ -417,7 +418,7 @@ void Wiimote::ReadData(const wm_read_data* const rd) { // reading the whole mii block :/ std::ifstream file; - file.open((File::GetUserPath(D_WIIUSER_IDX) + "mii.bin").c_str(), std::ios::binary | std::ios::in); + file.open((File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin").c_str(), std::ios::binary | std::ios::in); file.read((char*)m_eeprom + 0x0FCA, 0x02f0); file.close(); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp index c14186f6f0..5e300ce120 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp @@ -5,11 +5,14 @@ #include #include "Common/ChunkFile.h" +#include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" +#include "Core/Core.h" +#include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_fs.h" @@ -19,7 +22,7 @@ static Common::replace_v replacements; // This is used by several of the FileIO and /dev/fs functions std::string HLE_IPC_BuildFilename(std::string path_wii) { - std::string path_full = File::GetUserPath(D_WIIROOT_IDX); + std::string path_full = File::GetUserPath(D_SESSION_WIIROOT_IDX); // Replaces chars that FAT32 can't support with strings defined in /sys/replace for (auto& replacement : replacements) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp index 70368267f8..68108705fb 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp @@ -32,7 +32,7 @@ IPCCommandResult CWII_IPC_HLE_Device_fs::Open(u32 _CommandAddress, u32 _Mode) { // clear tmp folder { - std::string Path = File::GetUserPath(D_WIIUSER_IDX) + "tmp"; + std::string Path = HLE_IPC_BuildFilename("/tmp"); File::DeleteDirRecursively(Path); File::CreateDir(Path); } @@ -221,7 +221,6 @@ IPCCommandResult CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress) IPCCommandResult CWII_IPC_HLE_Device_fs::IOCtl(u32 _CommandAddress) { //u32 DeviceID = Memory::Read_U32(_CommandAddress + 8); - //LOG(WII_IPC_FILEIO, "FS: IOCtl (Device=%s, DeviceID=%08x)", GetDeviceName().c_str(), DeviceID); u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); @@ -483,7 +482,7 @@ void CWII_IPC_HLE_Device_fs::DoState(PointerWrap& p) // handle /tmp - std::string Path = File::GetUserPath(D_WIIUSER_IDX) + "tmp"; + std::string Path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/tmp"; if (p.GetMode() == PointerWrap::MODE_READ) { File::DeleteDirRecursively(Path); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h index b06b45f7d0..c1cecee67e 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h @@ -4,7 +4,9 @@ #pragma once +#include "Common/CommonPaths.h" #include "Common/FileUtil.h" +#include "Common/NandPaths.h" #include "Common/Timer.h" #include "Core/HW/EXI_DeviceIPL.h" @@ -172,7 +174,7 @@ private: public: NWC24Config() { - path = File::GetUserPath(D_WIIWC24_IDX) + "nwc24msg.cfg"; + path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_WC24CONF_DIR "/nwc24msg.cfg"; ReadConfig(); } @@ -211,7 +213,7 @@ public: { if (!File::Exists(path)) { - if (!File::CreateFullPath(File::GetUserPath(D_WIIWC24_IDX))) + if (!File::CreateFullPath(File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_WC24CONF_DIR)) { ERROR_LOG(WII_IPC_WC24, "Failed to create directory for WC24"); } @@ -322,7 +324,7 @@ class WiiNetConfig public: WiiNetConfig() { - path = File::GetUserPath(D_WIISYSCONF_IDX) + "net/02/config.dat"; + path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_SYSCONF_DIR "/net/02/config.dat"; ReadConfig(); } @@ -347,7 +349,7 @@ public: { if (!File::Exists(path)) { - if (!File::CreateFullPath(std::string(File::GetUserPath(D_WIISYSCONF_IDX) + "net/02/"))) + if (!File::CreateFullPath(std::string(File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_SYSCONF_DIR "/net/02/"))) { ERROR_LOG(WII_IPC_NET, "Failed to create directory for network config file"); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp index 456e181960..03c50a97ce 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp @@ -5,6 +5,7 @@ #include #include "Common/FileUtil.h" +#include "Common/NandPaths.h" #include "Core/Core.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h" #include "Core/IPC_HLE/WII_Socket.h" @@ -286,7 +287,7 @@ _SSL_NEW_ERROR: if (SSLID_VALID(sslID)) { WII_SSL* ssl = &_SSL[sslID]; - std::string cert_base_path(File::GetUserPath(D_WIIUSER_IDX)); + std::string cert_base_path = File::GetUserPath(D_SESSION_WIIROOT_IDX); int ret = x509_crt_parse_file(&ssl->clicert, (cert_base_path + "clientca.pem").c_str()); int pk_ret = pk_parse_keyfile(&ssl->pk, (cert_base_path + "clientcakey.pem").c_str(), nullptr); if (ret || pk_ret) @@ -343,9 +344,8 @@ _SSL_NEW_ERROR: if (SSLID_VALID(sslID)) { WII_SSL* ssl = &_SSL[sslID]; - std::string cert_base_path(File::GetUserPath(D_WIIUSER_IDX)); - int ret = x509_crt_parse_file(&ssl->cacert, (cert_base_path + "rootca.pem").c_str()); + int ret = x509_crt_parse_file(&ssl->cacert, (File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/rootca.pem").c_str()); if (ret) { x509_crt_free(&ssl->clicert); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp index c2bb9c9fe8..b4e3f149db 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp @@ -61,7 +61,7 @@ void CWII_IPC_HLE_Device_sdio_slot0::EventNotify() void CWII_IPC_HLE_Device_sdio_slot0::OpenInternal() { - const std::string filename = File::GetUserPath(D_WIIUSER_IDX) + "sd.raw"; + const std::string filename = File::GetUserPath(D_WIIROOT_IDX) + "/sd.raw"; m_Card.Open(filename, "r+b"); if (!m_Card) { diff --git a/Source/Core/Core/ec_wii.cpp b/Source/Core/Core/ec_wii.cpp index 272aacac8c..d786d8fe75 100644 --- a/Source/Core/Core/ec_wii.cpp +++ b/Source/Core/Core/ec_wii.cpp @@ -119,7 +119,7 @@ void make_blanksig_ec_cert(u8 *cert_out, const char *signer, const char *name, c EcWii::EcWii() { bool init = true; - std::string keys_path = File::GetUserPath(D_WIIUSER_IDX) + "keys.bin"; + std::string keys_path = File::GetUserPath(D_WIIROOT_IDX) + "/keys.bin"; if (File::Exists(keys_path)) { File::IOFile keys_f(keys_path, "rb"); diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp index 715ac6e878..c247713ee3 100644 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/NANDContentLoader.cpp @@ -35,7 +35,7 @@ void CSharedContent::UpdateLocation() { m_Elements.clear(); m_lastID = 0; - m_contentMap = StringFromFormat("%sshared1/content.map", File::GetUserPath(D_WIIUSER_IDX).c_str()); + m_contentMap = StringFromFormat("%s/shared1/content.map", File::GetUserPath(D_WIIROOT_IDX).c_str()); File::IOFile pFile(m_contentMap, "rb"); SElement Element; @@ -55,7 +55,7 @@ std::string CSharedContent::GetFilenameFromSHA1(const u8* _pHash) { if (memcmp(_pHash, Element.SHA1Hash, 20) == 0) { - return StringFromFormat("%sshared1/%c%c%c%c%c%c%c%c.app", File::GetUserPath(D_WIIUSER_IDX).c_str(), + return StringFromFormat("%s/shared1/%c%c%c%c%c%c%c%c.app", File::GetUserPath(D_WIIROOT_IDX).c_str(), Element.FileName[0], Element.FileName[1], Element.FileName[2], Element.FileName[3], Element.FileName[4], Element.FileName[5], Element.FileName[6], Element.FileName[7]); } @@ -80,7 +80,7 @@ std::string CSharedContent::AddSharedContent(const u8* _pHash) File::IOFile pFile(m_contentMap, "ab"); pFile.WriteArray(&Element, 1); - filename = StringFromFormat("%sshared1/%s.app", File::GetUserPath(D_WIIUSER_IDX).c_str(), id.c_str()); + filename = StringFromFormat("%s/shared1/%s.app", File::GetUserPath(D_WIIROOT_IDX).c_str(), id.c_str()); m_lastID++; } @@ -371,7 +371,7 @@ void cUIDsys::UpdateLocation() { m_Elements.clear(); m_lastUID = 0x00001000; - m_uidSys = StringFromFormat("%ssys/uid.sys", File::GetUserPath(D_WIIUSER_IDX).c_str()); + m_uidSys = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/sys/uid.sys"; File::IOFile pFile(m_uidSys, "rb"); SElement Element; diff --git a/Source/Core/DiscIO/VolumeCommon.cpp b/Source/Core/DiscIO/VolumeCommon.cpp index cb4386af68..6d3998d85c 100644 --- a/Source/Core/DiscIO/VolumeCommon.cpp +++ b/Source/Core/DiscIO/VolumeCommon.cpp @@ -33,8 +33,8 @@ std::vector IVolume::GetBanner(int* width, int* height) const GetTitleID((u8*)&TitleID); TitleID = Common::swap64(TitleID); - std::string file_name = StringFromFormat("%stitle/%08x/%08x/data/banner.bin", - File::GetUserPath(D_WIIUSER_IDX).c_str(), (u32)(TitleID >> 32), (u32)TitleID); + std::string file_name = StringFromFormat("%s/title/%08x/%08x/data/banner.bin", + File::GetUserPath(D_WIIROOT_IDX).c_str(), (u32)(TitleID >> 32), (u32)TitleID); if (!File::Exists(file_name)) return std::vector(); diff --git a/Source/Core/DolphinQt/GameList/GameFile.cpp b/Source/Core/DolphinQt/GameList/GameFile.cpp index e8cbe83f3c..b7ee748c52 100644 --- a/Source/Core/DolphinQt/GameList/GameFile.cpp +++ b/Source/Core/DolphinQt/GameList/GameFile.cpp @@ -292,7 +292,7 @@ const QString GameFile::GetWiiFSPath() const volume->GetTitleID((u8*)&title); title = Common::swap64(title); - path = StringFromFormat("%stitle/%08x/%08x/data/", File::GetUserPath(D_WIIUSER_IDX).c_str(), (u32)(title >> 32), (u32)title); + path = StringFromFormat("%s/title/%08x/%08x/data/", File::GetUserPath(D_WIIROOT_IDX).c_str(), (u32)(title >> 32), (u32)title); if (!File::Exists(path)) File::CreateFullPath(path); diff --git a/Source/Core/DolphinWX/Config/PathConfigPane.cpp b/Source/Core/DolphinWX/Config/PathConfigPane.cpp index 04e9f20aab..efde03d64d 100644 --- a/Source/Core/DolphinWX/Config/PathConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/PathConfigPane.cpp @@ -182,8 +182,6 @@ void PathConfigPane::OnNANDRootChanged(wxCommandEvent& event) m_nand_root_dirpicker->SetPath(StrToWxStr(nand_path)); SConfig::GetInstance().m_SYSCONF->UpdateLocation(); - DiscIO::cUIDsys::AccessInstance().UpdateLocation(); - DiscIO::CSharedContent::AccessInstance().UpdateLocation(); main_frame->UpdateWiiMenuChoice(); } diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp index a85586e7d5..f4b05a855c 100644 --- a/Source/Core/DolphinWX/ISOFile.cpp +++ b/Source/Core/DolphinWX/ISOFile.cpp @@ -259,8 +259,8 @@ const std::string GameListItem::GetWiiFSPath() const iso->GetTitleID((u8*)&title); title = Common::swap64(title); - const std::string path = StringFromFormat("%stitle/%08x/%08x/data/", - File::GetUserPath(D_WIIUSER_IDX).c_str(), (u32)(title>>32), (u32)title); + const std::string path = StringFromFormat("%s/title/%08x/%08x/data/", + File::GetUserPath(D_WIIROOT_IDX).c_str(), (u32)(title>>32), (u32)title); if (!File::Exists(path)) File::CreateFullPath(path); diff --git a/Source/Core/DolphinWX/MainAndroid.cpp b/Source/Core/DolphinWX/MainAndroid.cpp index 2f37f36240..95b816c50b 100644 --- a/Source/Core/DolphinWX/MainAndroid.cpp +++ b/Source/Core/DolphinWX/MainAndroid.cpp @@ -537,7 +537,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CreateUserFo { File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX)); File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX)); - File::CreateFullPath(File::GetUserPath(D_WIIUSER_IDX)); + File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP); File::CreateFullPath(File::GetUserPath(D_CACHE_IDX)); File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX)); File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX)); diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index f1fa25ff44..a8394d9ea4 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -51,8 +51,8 @@ void Shutdown() void CreateDirectories() { // Copy initial Wii NAND data from Sys to User. - File::CopyDir(File::GetSysDirectory() + WII_USER_DIR DIR_SEP, - File::GetUserPath(D_WIIUSER_IDX)); + File::CopyDir(File::GetSysDirectory() + WII_USER_DIR, + File::GetUserPath(D_WIIROOT_IDX)); File::CreateFullPath(File::GetUserPath(D_USER_IDX)); File::CreateFullPath(File::GetUserPath(D_CACHE_IDX)); From 138d72313e3916d62955b565c39e0768a180a464 Mon Sep 17 00:00:00 2001 From: comex Date: Wed, 19 Nov 2014 21:05:56 -0500 Subject: [PATCH 7/9] Add a quick check to ScheduleEvent_Threadsafe to ensure it doesn't happen in deterministic mode. --- Source/Core/Core/CoreTiming.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 8b92f72f35..727c4d3059 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -226,6 +226,12 @@ u64 GetIdleTicks() void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata) { _assert_msg_(POWERPC, !Core::IsCPUThread(), "ScheduleEvent_Threadsafe from wrong thread"); + if (Core::g_want_determinism) + { + ERROR_LOG(POWERPC, "Someone scheduled an off-thread \"%s\" event while netplay or movie play/record " + "was active. This is likely to cause a desync.", + event_types[event_type].name.c_str()); + } std::lock_guard lk(tsWriteLock); Event ne; ne.time = globalTimer + cyclesIntoFuture; From 0d257b9e88faf63b28b5f1a25bf86447e6d095ae Mon Sep 17 00:00:00 2001 From: comex Date: Wed, 19 Nov 2014 21:28:17 -0500 Subject: [PATCH 8/9] Don't randomly generate a serial number in deterministic mode. --- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index a33065a7c9..cfb40b126b 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -199,7 +199,10 @@ bool CBoot::SetupWiiMemory(DiscIO::IVolume::ECountry country) if (serno.empty() || serno == "000000000") { - serno = gen.generateSerialNumber(); + if (Core::g_want_determinism) + serno = "123456789"; + else + serno = gen.generateSerialNumber(); INFO_LOG(BOOT, "No previous serial number found, generated one instead: %s", serno.c_str()); } else From 45b07cbdcd97f2015dca5873c7949e9991ce23d4 Mon Sep 17 00:00:00 2001 From: comex Date: Mon, 20 Apr 2015 22:24:21 -0400 Subject: [PATCH 9/9] Fix determinism issues with Wiimote netplay. - Change the Wiimote emulation SYSCONF R/W to use the temporary NAND if in use. - Fix up SysConf API so this actually works. Kind of a hack. Like I said, this can be cleaned up when configuration is synced... --- Source/Core/Common/SysConf.cpp | 12 ++++++++---- .../Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp | 19 +++++++++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/Source/Core/Common/SysConf.cpp b/Source/Core/Common/SysConf.cpp index a0d3aa1f04..047114774a 100644 --- a/Source/Core/Common/SysConf.cpp +++ b/Source/Core/Common/SysConf.cpp @@ -38,6 +38,10 @@ void SysConf::Clear() bool SysConf::LoadFromFile(const std::string& filename) { + if (m_IsValid) + Clear(); + m_IsValid = false; + // Basic check if (!File::Exists(filename)) { @@ -67,6 +71,7 @@ bool SysConf::LoadFromFile(const std::string& filename) if (LoadFromFileInternal(f.ReleaseHandle())) { m_Filename = filename; + m_IsValid = true; return true; } } @@ -107,6 +112,7 @@ bool SysConf::LoadFromFileInternal(FILE *fh) f.ReadArray(curEntry.name, curEntry.nameLength); curEntry.name[curEntry.nameLength] = '\0'; // Get length of data + curEntry.data = nullptr; curEntry.dataLength = 0; switch (curEntry.type) { @@ -362,6 +368,7 @@ void SysConf::GenerateSysConf() g.WriteBytes("SCed", 4); m_Filename = m_FilenameDefault; + m_IsValid = true; } bool SysConf::SaveToFile(const std::string& filename) @@ -418,11 +425,8 @@ void SysConf::UpdateLocation() bool SysConf::Reload() { - if (m_IsValid) - Clear(); - std::string& filename = m_Filename.empty() ? m_FilenameDefault : m_Filename; - m_IsValid = LoadFromFile(filename); + LoadFromFile(filename); return m_IsValid; } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp index 243b121c9f..bfd90e4652 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Common/CommonPaths.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" @@ -35,11 +36,25 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _De , m_ACLEndpoint(0) , m_last_ticks(0) { + SysConf* sysconf; + std::unique_ptr owned_sysconf; + if (Core::g_want_determinism) + { + // See SysConf::UpdateLocation for comment about the Future. + owned_sysconf.reset(new SysConf()); + sysconf = owned_sysconf.get(); + sysconf->LoadFromFile(File::GetUserPath(D_SESSION_WIIROOT_IDX) + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF); + } + else + { + sysconf = SConfig::GetInstance().m_SYSCONF; + } + // Activate only first Wiimote by default _conf_pads BT_DINF; SetUsbPointer(this); - if (!SConfig::GetInstance().m_SYSCONF->GetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads))) + if (!sysconf->GetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads))) { PanicAlertT("Trying to read from invalid SYSCONF\nWiimote bt ids are not available"); } @@ -83,7 +98,7 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _De // save now so that when games load sysconf file it includes the new Wiimotes // and the correct order for connected Wiimotes - if (!SConfig::GetInstance().m_SYSCONF->SetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads)) || !SConfig::GetInstance().m_SYSCONF->Save()) + if (!sysconf->SetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads)) || !sysconf->Save()) PanicAlertT("Failed to write BT.DINF to SYSCONF"); }