From 320c0d06c3ab367b606e8413d22903314f91b56a Mon Sep 17 00:00:00 2001 From: KentuckyCompass Date: Thu, 10 Jan 2013 03:27:10 -0800 Subject: [PATCH] Implement per-thread current directory --- Core/FileSystems/MetaFileSystem.cpp | 68 ++++++++++++++++++++++++++--- Core/FileSystems/MetaFileSystem.h | 16 ++++--- Core/HLE/sceIo.cpp | 6 +++ Core/Loaders.cpp | 4 +- Core/System.cpp | 4 +- 5 files changed, 81 insertions(+), 17 deletions(-) diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index fde8036b2..e548f4475 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -17,6 +17,7 @@ #include #include "Common/StringUtil.h" +#include "../HLE/sceKernelThread.h" #include "MetaFileSystem.h" static bool ApplyPathStringToComponentsVector(std::vector &vector, const std::string &pathString) @@ -163,7 +164,6 @@ IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle) bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath, IFileSystem **system) { - //TODO: implement current directory per thread (NOT per drive) std::string realpath; // Special handling: host0:command.txt (as seen in Super Monkey Ball Adventures, for example) @@ -174,7 +174,22 @@ bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpat inpath = inpath.substr(6); } - if ( RealPath(currentDirectory, inpath, realpath) ) + const std::string *currentDirectory = &startingDirectory; + + int currentThread = __KernelGetCurThread(); + currentDir_t::iterator i = currentDir.find(currentThread); + if (i == currentDir.end()) + { + //TODO: emulate PSP's error 8002032C: "no current working directory" if relative... may break things requiring fixes elsewhere + if (inpath.find(':') == std::string::npos /* means path is relative */) + WARN_LOG(HLE, "Path is relative, but current directory not set for thread %i. Should give error, instead falling back to %s", currentThread, startingDirectory.c_str()); + } + else + { + currentDirectory = &(i->second); + } + + if ( RealPath(*currentDirectory, inpath, realpath) ) { for (size_t i = 0; i < fileSystems.size(); i++) { @@ -203,7 +218,7 @@ void MetaFileSystem::Mount(std::string prefix, IFileSystem *system) fileSystems.push_back(x); } -void MetaFileSystem::UnmountAll() +void MetaFileSystem::Shutdown() { current = 6; @@ -220,7 +235,8 @@ void MetaFileSystem::UnmountAll() } fileSystems.clear(); - currentDirectory = ""; + currentDir.clear(); + startingDirectory = ""; } u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access) @@ -278,6 +294,19 @@ std::vector MetaFileSystem::GetDirListing(std::string path) } } +void MetaFileSystem::ThreadEnded(int threadID) +{ + currentDir.erase(threadID); +} + +void MetaFileSystem::ChDir(const std::string &dir) +{ + //TODO: test sceIoChdir("..") on PSP - maybe we should map it before saving it? + + int curThread = __KernelGetCurThread(); + currentDir[curThread] = dir; +} + bool MetaFileSystem::MkDir(const std::string &dirname) { std::string of; @@ -372,9 +401,34 @@ size_t MetaFileSystem::SeekFile(u32 handle, s32 position, FileMove type) void MetaFileSystem::DoState(PointerWrap &p) { p.Do(current); - p.Do(currentDirectory); - int n = (int) fileSystems.size(); + // Save/load per-thread current directory map + u32 n = (u32) currentDir.size(); + p.Do(n); + if (p.mode == p.MODE_READ) + { + std::string dir; + currentDir.clear(); + for (u32 i = 0; i < n; ++i) + { + int threadID; + p.Do(threadID); + p.Do(dir); + + currentDir[threadID] = dir; + } + } + else + { + currentDir_t::iterator i = currentDir.begin(), end = currentDir.end(); + for (; i != end; ++i) + { + p.Do(i->first); + p.Do(i->second); + } + } + + n = (u32) fileSystems.size(); p.Do(n); if (n != fileSystems.size()) { @@ -382,7 +436,7 @@ void MetaFileSystem::DoState(PointerWrap &p) return; } - for (int i = 0; i < n; ++i) + for (u32 i = 0; i < n; ++i) fileSystems[i].system->DoState(p); p.DoMarker("MetaFileSystem"); diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index 88fc50d23..17eeb4ca5 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -30,8 +30,9 @@ public: void Mount(std::string prefix, IFileSystem *system); void Unmount(IFileSystem *system); - // Effectively "Shutdown". - void UnmountAll(); + void ThreadEnded(int threadID); + + void Shutdown(); u32 GetNewHandle() {return current++;} void FreeHandle(u32 handle) {} @@ -57,7 +58,7 @@ public: return SeekFile(handle, 0, FILEMOVE_CURRENT); } - virtual void ChDir(std::string dir) {currentDirectory = dir;} + virtual void ChDir(const std::string &dir); virtual bool MkDir(const std::string &dirname); virtual bool RmDir(const std::string &dirname); @@ -66,8 +67,8 @@ public: // TODO: void IoCtl(...) - void SetCurrentDirectory(const std::string &dir) { - currentDirectory = dir; + void SetStartingDirectory(const std::string &dir) { + startingDirectory = dir; } private: u32 current; @@ -78,5 +79,8 @@ private: }; std::vector fileSystems; - std::string currentDirectory; + typedef std::map currentDir_t; + currentDir_t currentDir; + + std::string startingDirectory; }; diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 5910bd31c..177f531c0 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -159,6 +159,10 @@ public: PSPFileInfo info; }; +void TellFsThreadEnded (SceUID threadID) { + pspFileSystem.ThreadEnded(threadID); +} + void __IoInit() { INFO_LOG(HLE, "Starting up I/O..."); @@ -199,6 +203,8 @@ void __IoInit() { pspFileSystem.Mount("fatms:", memstick); pspFileSystem.Mount("flash0:", flash); pspFileSystem.Mount("flash1:", flash); + + __KernelListenThreadEnd(&TellFsThreadEnded); } void __IoDoState(PointerWrap &p) { diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index c51da638a..7bffa5ecb 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -92,11 +92,11 @@ bool LoadFile(const char *filename, std::string *error_string) // If loading from memstick... size_t pos = path.find("/PSP/GAME/"); if (pos != std::string::npos) - pspFileSystem.SetCurrentDirectory("ms0:" + path.substr(pos)); + pspFileSystem.SetStartingDirectory("ms0:" + path.substr(pos)); return Load_PSP_ELF_PBP(filename, error_string); } case FILETYPE_PSP_ISO: - pspFileSystem.SetCurrentDirectory("disc0:/PSP_GAME/USRDIR"); + pspFileSystem.SetStartingDirectory("disc0:/PSP_GAME/USRDIR"); return Load_PSP_ISO(filename, error_string); case FILETYPE_ERROR: ERROR_LOG(LOADER, "Could not file"); diff --git a/Core/System.cpp b/Core/System.cpp index 67c3b74cd..1e7e6c824 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -64,7 +64,7 @@ bool PSP_Init(const CoreParameter &coreParam, std::string *error_string) if (!LoadFile(coreParameter.fileToStart.c_str(), error_string)) { - pspFileSystem.UnmountAll(); + pspFileSystem.Shutdown(); CoreTiming::ClearPendingEvents(); CoreTiming::UnregisterAllEvents(); __KernelShutdown(); @@ -90,7 +90,7 @@ bool PSP_IsInited() void PSP_Shutdown() { - pspFileSystem.UnmountAll(); + pspFileSystem.Shutdown(); TextureCache_Clear(true);