summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar bunnei2014-06-25 17:32:09 -0400
committerGravatar bunnei2014-06-27 16:58:30 -0400
commit0cc3e85685496f1dd5b742c42d0b2903b9f0c735 (patch)
treeffa194504437d7ee6e7ff7814140efe0751bd638 /src/core
parentMerge pull request #22 from bunnei/loader-improvements (diff)
downloadyuzu-0cc3e85685496f1dd5b742c42d0b2903b9f0c735.tar.gz
yuzu-0cc3e85685496f1dd5b742c42d0b2903b9f0c735.tar.xz
yuzu-0cc3e85685496f1dd5b742c42d0b2903b9f0c735.zip
Core: Removed unused directory_file_system and meta_file_system modules.
Core: Updated CMakeLists.txt to remove directory_file_system and meta_file_system modules.
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/core.vcxproj4
-rw-r--r--src/core/core.vcxproj.filters12
-rw-r--r--src/core/file_sys/directory_file_system.cpp669
-rw-r--r--src/core/file_sys/directory_file_system.h155
-rw-r--r--src/core/file_sys/meta_file_system.cpp519
-rw-r--r--src/core/file_sys/meta_file_system.h110
-rw-r--r--src/core/system.cpp2
-rw-r--r--src/core/system.h2
9 files changed, 0 insertions, 1477 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 634f4d572..e534f07c4 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -29,8 +29,6 @@ set(SRCS core.cpp
29 arm/interpreter/mmu/tlb.cpp 29 arm/interpreter/mmu/tlb.cpp
30 arm/interpreter/mmu/wb.cpp 30 arm/interpreter/mmu/wb.cpp
31 arm/interpreter/mmu/xscale_copro.cpp 31 arm/interpreter/mmu/xscale_copro.cpp
32 file_sys/directory_file_system.cpp
33 file_sys/meta_file_system.cpp
34 hle/hle.cpp 32 hle/hle.cpp
35 hle/config_mem.cpp 33 hle/config_mem.cpp
36 hle/coprocessor.cpp 34 hle/coprocessor.cpp
@@ -75,9 +73,7 @@ set(HEADERS core.h
75 arm/interpreter/vfp/asm_vfp.h 73 arm/interpreter/vfp/asm_vfp.h
76 arm/interpreter/vfp/vfp.h 74 arm/interpreter/vfp/vfp.h
77 arm/interpreter/vfp/vfp_helper.h 75 arm/interpreter/vfp/vfp_helper.h
78 file_sys/directory_file_system.h
79 file_sys/file_sys.h 76 file_sys/file_sys.h
80 file_sys/meta_file_system.h
81 hle/config_mem.h 77 hle/config_mem.h
82 hle/coprocessor.h 78 hle/coprocessor.h
83 hle/hle.h 79 hle/hle.h
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index e2216760a..d92825a0e 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -162,8 +162,6 @@
162 <ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp" /> 162 <ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp" />
163 <ClCompile Include="core.cpp" /> 163 <ClCompile Include="core.cpp" />
164 <ClCompile Include="core_timing.cpp" /> 164 <ClCompile Include="core_timing.cpp" />
165 <ClCompile Include="file_sys\directory_file_system.cpp" />
166 <ClCompile Include="file_sys\meta_file_system.cpp" />
167 <ClCompile Include="hle\config_mem.cpp" /> 165 <ClCompile Include="hle\config_mem.cpp" />
168 <ClCompile Include="hle\coprocessor.cpp" /> 166 <ClCompile Include="hle\coprocessor.cpp" />
169 <ClCompile Include="hle\hle.cpp" /> 167 <ClCompile Include="hle\hle.cpp" />
@@ -211,9 +209,7 @@
211 <ClInclude Include="arm\interpreter\vfp\vfp_helper.h" /> 209 <ClInclude Include="arm\interpreter\vfp\vfp_helper.h" />
212 <ClInclude Include="core.h" /> 210 <ClInclude Include="core.h" />
213 <ClInclude Include="core_timing.h" /> 211 <ClInclude Include="core_timing.h" />
214 <ClInclude Include="file_sys\directory_file_system.h" />
215 <ClInclude Include="file_sys\file_sys.h" /> 212 <ClInclude Include="file_sys\file_sys.h" />
216 <ClInclude Include="file_sys\meta_file_system.h" />
217 <ClInclude Include="hle\config_mem.h" /> 213 <ClInclude Include="hle\config_mem.h" />
218 <ClInclude Include="hle\coprocessor.h" /> 214 <ClInclude Include="hle\coprocessor.h" />
219 <ClInclude Include="hle\function_wrappers.h" /> 215 <ClInclude Include="hle\function_wrappers.h" />
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index 91d3292da..8f1751c5d 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -63,12 +63,6 @@
63 <ClCompile Include="arm\interpreter\thumbemu.cpp"> 63 <ClCompile Include="arm\interpreter\thumbemu.cpp">
64 <Filter>arm\interpreter</Filter> 64 <Filter>arm\interpreter</Filter>
65 </ClCompile> 65 </ClCompile>
66 <ClCompile Include="file_sys\directory_file_system.cpp">
67 <Filter>file_sys</Filter>
68 </ClCompile>
69 <ClCompile Include="file_sys\meta_file_system.cpp">
70 <Filter>file_sys</Filter>
71 </ClCompile>
72 <ClCompile Include="hw\hw.cpp"> 66 <ClCompile Include="hw\hw.cpp">
73 <Filter>hw</Filter> 67 <Filter>hw</Filter>
74 </ClCompile> 68 </ClCompile>
@@ -205,15 +199,9 @@
205 <ClInclude Include="arm\interpreter\skyeye_defs.h"> 199 <ClInclude Include="arm\interpreter\skyeye_defs.h">
206 <Filter>arm\interpreter</Filter> 200 <Filter>arm\interpreter</Filter>
207 </ClInclude> 201 </ClInclude>
208 <ClInclude Include="file_sys\directory_file_system.h">
209 <Filter>file_sys</Filter>
210 </ClInclude>
211 <ClInclude Include="file_sys\file_sys.h"> 202 <ClInclude Include="file_sys\file_sys.h">
212 <Filter>file_sys</Filter> 203 <Filter>file_sys</Filter>
213 </ClInclude> 204 </ClInclude>
214 <ClInclude Include="file_sys\meta_file_system.h">
215 <Filter>file_sys</Filter>
216 </ClInclude>
217 <ClInclude Include="hw\hw.h"> 205 <ClInclude Include="hw\hw.h">
218 <Filter>hw</Filter> 206 <Filter>hw</Filter>
219 </ClInclude> 207 </ClInclude>
diff --git a/src/core/file_sys/directory_file_system.cpp b/src/core/file_sys/directory_file_system.cpp
deleted file mode 100644
index 6c6f33c2b..000000000
--- a/src/core/file_sys/directory_file_system.cpp
+++ /dev/null
@@ -1,669 +0,0 @@
1// Copyright (c) 2012- PPSSPP Project.
2
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, version 2.0 or later versions.
6
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU General Public License 2.0 for more details.
11
12// A copy of the GPL 2.0 should have been included with the program.
13// If not, see http://www.gnu.org/licenses/
14
15// Official git repository and contact information can be found at
16// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18#include "common/chunk_file.h"
19#include "common/file_util.h"
20#include "common/utf8.h"
21
22#include "core/file_sys/directory_file_system.h"
23
24#if EMU_PLATFORM == PLATFORM_WINDOWS
25#include <windows.h>
26#include <sys/stat.h>
27#else
28#include <dirent.h>
29#include <unistd.h>
30#include <sys/stat.h>
31#include <ctype.h>
32#endif
33
34#if HOST_IS_CASE_SENSITIVE
35static bool FixFilenameCase(const std::string &path, std::string &filename)
36{
37 // Are we lucky?
38 if (File::Exists(path + filename))
39 return true;
40
41 size_t filenameSize = filename.size(); // size in bytes, not characters
42 for (size_t i = 0; i < filenameSize; i++)
43 {
44 filename[i] = tolower(filename[i]);
45 }
46
47 //TODO: lookup filename in cache for "path"
48
49 struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; } diren;
50 struct dirent_large;
51 struct dirent *result = NULL;
52
53 DIR *dirp = opendir(path.c_str());
54 if (!dirp)
55 return false;
56
57 bool retValue = false;
58
59 while (!readdir_r(dirp, (dirent*) &diren, &result) && result)
60 {
61 if (strlen(result->d_name) != filenameSize)
62 continue;
63
64 size_t i;
65 for (i = 0; i < filenameSize; i++)
66 {
67 if (filename[i] != tolower(result->d_name[i]))
68 break;
69 }
70
71 if (i < filenameSize)
72 continue;
73
74 filename = result->d_name;
75 retValue = true;
76 }
77
78 closedir(dirp);
79
80 return retValue;
81}
82
83bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior)
84{
85 size_t len = path.size();
86
87 if (len == 0)
88 return true;
89
90 if (path[len - 1] == '/')
91 {
92 len--;
93
94 if (len == 0)
95 return true;
96 }
97
98 std::string fullPath;
99 fullPath.reserve(basePath.size() + len + 1);
100 fullPath.append(basePath);
101
102 size_t start = 0;
103 while (start < len)
104 {
105 size_t i = path.find('/', start);
106 if (i == std::string::npos)
107 i = len;
108
109 if (i > start)
110 {
111 std::string component = path.substr(start, i - start);
112
113 // Fix case and stop on nonexistant path component
114 if (FixFilenameCase(fullPath, component) == false) {
115 // Still counts as success if partial matches allowed or if this
116 // is the last component and only the ones before it are required
117 return (behavior == FPC_PARTIAL_ALLOWED || (behavior == FPC_PATH_MUST_EXIST && i >= len));
118 }
119
120 path.replace(start, i - start, component);
121
122 fullPath.append(component);
123 fullPath.append(1, '/');
124 }
125
126 start = i + 1;
127 }
128
129 return true;
130}
131
132#endif
133
134std::string DirectoryFileHandle::GetLocalPath(std::string& basePath, std::string localpath)
135{
136 if (localpath.empty())
137 return basePath;
138
139 if (localpath[0] == '/')
140 localpath.erase(0,1);
141 //Convert slashes
142#ifdef _WIN32
143 for (size_t i = 0; i < localpath.size(); i++) {
144 if (localpath[i] == '/')
145 localpath[i] = '\\';
146 }
147#endif
148 return basePath + localpath;
149}
150
151bool DirectoryFileHandle::Open(std::string& basePath, std::string& fileName, FileAccess access)
152{
153#if HOST_IS_CASE_SENSITIVE
154 if (access & (FILEACCESS_APPEND|FILEACCESS_CREATE|FILEACCESS_WRITE))
155 {
156 DEBUG_LOG(FILESYS, "Checking case for path %s", fileName.c_str());
157 if ( ! FixPathCase(basePath, fileName, FPC_PATH_MUST_EXIST) )
158 return false; // or go on and attempt (for a better error code than just 0?)
159 }
160 // else we try fopen first (in case we're lucky) before simulating case insensitivity
161#endif
162
163 std::string fullName = GetLocalPath(basePath,fileName);
164 INFO_LOG(FILESYS,"Actually opening %s", fullName.c_str());
165
166 //TODO: tests, should append seek to end of file? seeking in a file opened for append?
167#ifdef _WIN32
168 // Convert parameters to Windows permissions and access
169 DWORD desired = 0;
170 DWORD sharemode = 0;
171 DWORD openmode = 0;
172 if (access & FILEACCESS_READ) {
173 desired |= GENERIC_READ;
174 sharemode |= FILE_SHARE_READ;
175 }
176 if (access & FILEACCESS_WRITE) {
177 desired |= GENERIC_WRITE;
178 sharemode |= FILE_SHARE_WRITE;
179 }
180 if (access & FILEACCESS_CREATE) {
181 openmode = OPEN_ALWAYS;
182 } else {
183 openmode = OPEN_EXISTING;
184 }
185 //Let's do it!
186 hFile = CreateFile(ConvertUTF8ToWString(fullName).c_str(), desired, sharemode, 0, openmode, 0, 0);
187 bool success = hFile != INVALID_HANDLE_VALUE;
188#else
189 // Convert flags in access parameter to fopen access mode
190 const char *mode = NULL;
191 if (access & FILEACCESS_APPEND) {
192 if (access & FILEACCESS_READ)
193 mode = "ab+"; // append+read, create if needed
194 else
195 mode = "ab"; // append only, create if needed
196 } else if (access & FILEACCESS_WRITE) {
197 if (access & FILEACCESS_READ) {
198 // FILEACCESS_CREATE is ignored for read only, write only, and append
199 // because C++ standard fopen's nonexistant file creation can only be
200 // customized for files opened read+write
201 if (access & FILEACCESS_CREATE)
202 mode = "wb+"; // read+write, create if needed
203 else
204 mode = "rb+"; // read+write, but don't create
205 } else {
206 mode = "wb"; // write only, create if needed
207 }
208 } else { // neither write nor append, so default to read only
209 mode = "rb"; // read only, don't create
210 }
211
212 hFile = fopen(fullName.c_str(), mode);
213 bool success = hFile != 0;
214#endif
215
216#if HOST_IS_CASE_SENSITIVE
217 if (!success &&
218 !(access & FILEACCESS_APPEND) &&
219 !(access & FILEACCESS_CREATE) &&
220 !(access & FILEACCESS_WRITE))
221 {
222 if ( ! FixPathCase(basePath,fileName, FPC_PATH_MUST_EXIST) )
223 return 0; // or go on and attempt (for a better error code than just 0?)
224 fullName = GetLocalPath(basePath,fileName);
225 const char* fullNameC = fullName.c_str();
226
227 DEBUG_LOG(FILESYS, "Case may have been incorrect, second try opening %s (%s)", fullNameC, fileName.c_str());
228
229 // And try again with the correct case this time
230#ifdef _WIN32
231 hFile = CreateFile(fullNameC, desired, sharemode, 0, openmode, 0, 0);
232 success = hFile != INVALID_HANDLE_VALUE;
233#else
234 hFile = fopen(fullNameC, mode);
235 success = hFile != 0;
236#endif
237 }
238#endif
239
240 return success;
241}
242
243size_t DirectoryFileHandle::Read(u8* pointer, s64 size)
244{
245 size_t bytesRead = 0;
246#ifdef _WIN32
247 ::ReadFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesRead, 0);
248#else
249 bytesRead = fread(pointer, 1, size, hFile);
250#endif
251 return bytesRead;
252}
253
254size_t DirectoryFileHandle::Write(const u8* pointer, s64 size)
255{
256 size_t bytesWritten = 0;
257#ifdef _WIN32
258 ::WriteFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesWritten, 0);
259#else
260 bytesWritten = fwrite(pointer, 1, size, hFile);
261#endif
262 return bytesWritten;
263}
264
265size_t DirectoryFileHandle::Seek(s32 position, FileMove type)
266{
267#ifdef _WIN32
268 DWORD moveMethod = 0;
269 switch (type) {
270 case FILEMOVE_BEGIN: moveMethod = FILE_BEGIN; break;
271 case FILEMOVE_CURRENT: moveMethod = FILE_CURRENT; break;
272 case FILEMOVE_END: moveMethod = FILE_END; break;
273 }
274 DWORD newPos = SetFilePointer(hFile, (LONG)position, 0, moveMethod);
275 return newPos;
276#else
277 int moveMethod = 0;
278 switch (type) {
279 case FILEMOVE_BEGIN: moveMethod = SEEK_SET; break;
280 case FILEMOVE_CURRENT: moveMethod = SEEK_CUR; break;
281 case FILEMOVE_END: moveMethod = SEEK_END; break;
282 }
283 fseek(hFile, position, moveMethod);
284 return ftell(hFile);
285#endif
286}
287
288void DirectoryFileHandle::Close()
289{
290#ifdef _WIN32
291 if (hFile != (HANDLE)-1)
292 CloseHandle(hFile);
293#else
294 if (hFile != 0)
295 fclose(hFile);
296#endif
297}
298
299DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath) {
300 File::CreateFullPath(basePath);
301 hAlloc = _hAlloc;
302}
303
304DirectoryFileSystem::~DirectoryFileSystem() {
305 for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
306 iter->second.hFile.Close();
307 }
308}
309
310std::string DirectoryFileSystem::GetLocalPath(std::string localpath) {
311 if (localpath.empty())
312 return basePath;
313
314 if (localpath[0] == '/')
315 localpath.erase(0,1);
316 //Convert slashes
317#ifdef _WIN32
318 for (size_t i = 0; i < localpath.size(); i++) {
319 if (localpath[i] == '/')
320 localpath[i] = '\\';
321 }
322#endif
323 return basePath + localpath;
324}
325
326bool DirectoryFileSystem::MkDir(const std::string &dirname) {
327#if HOST_IS_CASE_SENSITIVE
328 // Must fix case BEFORE attempting, because MkDir would create
329 // duplicate (different case) directories
330
331 std::string fixedCase = dirname;
332 if ( ! FixPathCase(basePath,fixedCase, FPC_PARTIAL_ALLOWED) )
333 return false;
334
335 return File::CreateFullPath(GetLocalPath(fixedCase));
336#else
337 return File::CreateFullPath(GetLocalPath(dirname));
338#endif
339}
340
341bool DirectoryFileSystem::RmDir(const std::string &dirname) {
342 std::string fullName = GetLocalPath(dirname);
343
344#if HOST_IS_CASE_SENSITIVE
345 // Maybe we're lucky?
346 if (File::DeleteDirRecursively(fullName))
347 return true;
348
349 // Nope, fix case and try again
350 fullName = dirname;
351 if ( ! FixPathCase(basePath,fullName, FPC_FILE_MUST_EXIST) )
352 return false; // or go on and attempt (for a better error code than just false?)
353
354 fullName = GetLocalPath(fullName);
355#endif
356
357/*#ifdef _WIN32
358 return RemoveDirectory(fullName.c_str()) == TRUE;
359#else
360 return 0 == rmdir(fullName.c_str());
361#endif*/
362 return File::DeleteDirRecursively(fullName);
363}
364
365int DirectoryFileSystem::RenameFile(const std::string &from, const std::string &to) {
366 std::string fullTo = to;
367
368 // Rename ignores the path (even if specified) on to.
369 size_t chop_at = to.find_last_of('/');
370 if (chop_at != to.npos)
371 fullTo = to.substr(chop_at + 1);
372
373 // Now put it in the same directory as from.
374 size_t dirname_end = from.find_last_of('/');
375 if (dirname_end != from.npos)
376 fullTo = from.substr(0, dirname_end + 1) + fullTo;
377
378 // At this point, we should check if the paths match and give an already exists error.
379 if (from == fullTo)
380 return -1;//SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS;
381
382 std::string fullFrom = GetLocalPath(from);
383
384#if HOST_IS_CASE_SENSITIVE
385 // In case TO should overwrite a file with different case
386 if ( ! FixPathCase(basePath,fullTo, FPC_PATH_MUST_EXIST) )
387 return -1; // or go on and attempt (for a better error code than just false?)
388#endif
389
390 fullTo = GetLocalPath(fullTo);
391 const char * fullToC = fullTo.c_str();
392
393#ifdef _WIN32
394 bool retValue = (MoveFile(ConvertUTF8ToWString(fullFrom).c_str(), ConvertUTF8ToWString(fullToC).c_str()) == TRUE);
395#else
396 bool retValue = (0 == rename(fullFrom.c_str(), fullToC));
397#endif
398
399#if HOST_IS_CASE_SENSITIVE
400 if (! retValue)
401 {
402 // May have failed due to case sensitivity on FROM, so try again
403 fullFrom = from;
404 if ( ! FixPathCase(basePath,fullFrom, FPC_FILE_MUST_EXIST) )
405 return -1; // or go on and attempt (for a better error code than just false?)
406 fullFrom = GetLocalPath(fullFrom);
407
408#ifdef _WIN32
409 retValue = (MoveFile(fullFrom.c_str(), fullToC) == TRUE);
410#else
411 retValue = (0 == rename(fullFrom.c_str(), fullToC));
412#endif
413 }
414#endif
415
416 // TODO: Better error codes.
417 return retValue ? 0 : -1;//SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS;
418}
419
420bool DirectoryFileSystem::RemoveFile(const std::string &filename) {
421 std::string fullName = GetLocalPath(filename);
422#ifdef _WIN32
423 bool retValue = (::DeleteFileA(fullName.c_str()) == TRUE);
424#else
425 bool retValue = (0 == unlink(fullName.c_str()));
426#endif
427
428#if HOST_IS_CASE_SENSITIVE
429 if (! retValue)
430 {
431 // May have failed due to case sensitivity, so try again
432 fullName = filename;
433 if ( ! FixPathCase(basePath,fullName, FPC_FILE_MUST_EXIST) )
434 return false; // or go on and attempt (for a better error code than just false?)
435 fullName = GetLocalPath(fullName);
436
437#ifdef _WIN32
438 retValue = (::DeleteFileA(fullName.c_str()) == TRUE);
439#else
440 retValue = (0 == unlink(fullName.c_str()));
441#endif
442 }
443#endif
444
445 return retValue;
446}
447
448u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) {
449 OpenFileEntry entry;
450 bool success = entry.hFile.Open(basePath,filename,access);
451
452 if (!success) {
453#ifdef _WIN32
454 ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, %i - access = %i", GetLastError(), (int)access);
455#else
456 ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, access = %i", (int)access);
457#endif
458 //wwwwaaaaahh!!
459 return 0;
460 } else {
461#ifdef _WIN32
462 if (access & FILEACCESS_APPEND)
463 entry.hFile.Seek(0,FILEMOVE_END);
464#endif
465
466 u32 newHandle = hAlloc->GetNewHandle();
467 entries[newHandle] = entry;
468
469 return newHandle;
470 }
471}
472
473void DirectoryFileSystem::CloseFile(u32 handle) {
474 EntryMap::iterator iter = entries.find(handle);
475 if (iter != entries.end()) {
476 hAlloc->FreeHandle(handle);
477 iter->second.hFile.Close();
478 entries.erase(iter);
479 } else {
480 //This shouldn't happen...
481 ERROR_LOG(FILESYS,"Cannot close file that hasn't been opened: %08x", handle);
482 }
483}
484
485bool DirectoryFileSystem::OwnsHandle(u32 handle) {
486 EntryMap::iterator iter = entries.find(handle);
487 return (iter != entries.end());
488}
489
490size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
491 EntryMap::iterator iter = entries.find(handle);
492 if (iter != entries.end())
493 {
494 size_t bytesRead = iter->second.hFile.Read(pointer,size);
495 return bytesRead;
496 } else {
497 //This shouldn't happen...
498 ERROR_LOG(FILESYS,"Cannot read file that hasn't been opened: %08x", handle);
499 return 0;
500 }
501}
502
503size_t DirectoryFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) {
504 EntryMap::iterator iter = entries.find(handle);
505 if (iter != entries.end())
506 {
507 size_t bytesWritten = iter->second.hFile.Write(pointer,size);
508 return bytesWritten;
509 } else {
510 //This shouldn't happen...
511 ERROR_LOG(FILESYS,"Cannot write to file that hasn't been opened: %08x", handle);
512 return 0;
513 }
514}
515
516size_t DirectoryFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
517 EntryMap::iterator iter = entries.find(handle);
518 if (iter != entries.end()) {
519 return iter->second.hFile.Seek(position,type);
520 } else {
521 //This shouldn't happen...
522 ERROR_LOG(FILESYS,"Cannot seek in file that hasn't been opened: %08x", handle);
523 return 0;
524 }
525}
526
527FileInfo DirectoryFileSystem::GetFileInfo(std::string filename) {
528 FileInfo x;
529 x.name = filename;
530
531 std::string fullName = GetLocalPath(filename);
532 if (! File::Exists(fullName)) {
533#if HOST_IS_CASE_SENSITIVE
534 if (! FixPathCase(basePath,filename, FPC_FILE_MUST_EXIST))
535 return x;
536 fullName = GetLocalPath(filename);
537
538 if (! File::Exists(fullName))
539 return x;
540#else
541 return x;
542#endif
543 }
544 x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
545 x.exists = true;
546
547 if (x.type != FILETYPE_DIRECTORY)
548 {
549#ifdef _WIN32
550 struct _stat64i32 s;
551 _wstat64i32(ConvertUTF8ToWString(fullName).c_str(), &s);
552#else
553 struct stat s;
554 stat(fullName.c_str(), &s);
555#endif
556
557 x.size = File::GetSize(fullName);
558 x.access = s.st_mode & 0x1FF;
559 localtime_r((time_t*)&s.st_atime,&x.atime);
560 localtime_r((time_t*)&s.st_ctime,&x.ctime);
561 localtime_r((time_t*)&s.st_mtime,&x.mtime);
562 }
563
564 return x;
565}
566
567bool DirectoryFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) {
568 outpath = GetLocalPath(inpath);
569 return true;
570}
571
572#ifdef _WIN32
573#define FILETIME_FROM_UNIX_EPOCH_US 11644473600000000ULL
574
575static void tmFromFiletime(tm &dest, FILETIME &src)
576{
577 u64 from_1601_us = (((u64) src.dwHighDateTime << 32ULL) + (u64) src.dwLowDateTime) / 10ULL;
578 u64 from_1970_us = from_1601_us - FILETIME_FROM_UNIX_EPOCH_US;
579
580 time_t t = (time_t) (from_1970_us / 1000000UL);
581 localtime_r(&t, &dest);
582}
583#endif
584
585std::vector<FileInfo> DirectoryFileSystem::GetDirListing(std::string path) {
586 std::vector<FileInfo> myVector;
587#ifdef _WIN32
588 WIN32_FIND_DATA findData;
589 HANDLE hFind;
590
591 std::string w32path = GetLocalPath(path) + "\\*.*";
592
593 hFind = FindFirstFile(ConvertUTF8ToWString(w32path).c_str(), &findData);
594
595 if (hFind == INVALID_HANDLE_VALUE) {
596 return myVector; //the empty list
597 }
598
599 while (true) {
600 FileInfo entry;
601 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
602 entry.type = FILETYPE_DIRECTORY;
603 else
604 entry.type = FILETYPE_NORMAL;
605
606 // TODO: Make this more correct?
607 entry.access = entry.type == FILETYPE_NORMAL ? 0666 : 0777;
608 // TODO: is this just for .. or all subdirectories? Need to add a directory to the test
609 // to find out. Also why so different than the old test results?
610 if (!wcscmp(findData.cFileName, L"..") )
611 entry.size = 4096;
612 else
613 entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32);
614 entry.name = ConvertWStringToUTF8(findData.cFileName);
615 tmFromFiletime(entry.atime, findData.ftLastAccessTime);
616 tmFromFiletime(entry.ctime, findData.ftCreationTime);
617 tmFromFiletime(entry.mtime, findData.ftLastWriteTime);
618 myVector.push_back(entry);
619
620 int retval = FindNextFile(hFind, &findData);
621 if (!retval)
622 break;
623 }
624#else
625 dirent *dirp;
626 std::string localPath = GetLocalPath(path);
627 DIR *dp = opendir(localPath.c_str());
628
629#if HOST_IS_CASE_SENSITIVE
630 if(dp == NULL && FixPathCase(basePath,path, FPC_FILE_MUST_EXIST)) {
631 // May have failed due to case sensitivity, try again
632 localPath = GetLocalPath(path);
633 dp = opendir(localPath.c_str());
634 }
635#endif
636
637 if (dp == NULL) {
638 ERROR_LOG(FILESYS,"Error opening directory %s\n",path.c_str());
639 return myVector;
640 }
641
642 while ((dirp = readdir(dp)) != NULL) {
643 FileInfo entry;
644 struct stat s;
645 std::string fullName = GetLocalPath(path) + "/"+dirp->d_name;
646 stat(fullName.c_str(), &s);
647 if (S_ISDIR(s.st_mode))
648 entry.type = FILETYPE_DIRECTORY;
649 else
650 entry.type = FILETYPE_NORMAL;
651 entry.access = s.st_mode & 0x1FF;
652 entry.name = dirp->d_name;
653 entry.size = s.st_size;
654 localtime_r((time_t*)&s.st_atime,&entry.atime);
655 localtime_r((time_t*)&s.st_ctime,&entry.ctime);
656 localtime_r((time_t*)&s.st_mtime,&entry.mtime);
657 myVector.push_back(entry);
658 }
659 closedir(dp);
660#endif
661 return myVector;
662}
663
664void DirectoryFileSystem::DoState(PointerWrap &p) {
665 if (!entries.empty()) {
666 p.SetError(p.ERROR_WARNING);
667 ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly.");
668 }
669}
diff --git a/src/core/file_sys/directory_file_system.h b/src/core/file_sys/directory_file_system.h
deleted file mode 100644
index 9af2854a2..000000000
--- a/src/core/file_sys/directory_file_system.h
+++ /dev/null
@@ -1,155 +0,0 @@
1// Copyright (c) 2012- PPSSPP Project.
2
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, version 2.0 or later versions.
6
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU General Public License 2.0 for more details.
11
12// A copy of the GPL 2.0 should have been included with the program.
13// If not, see http://www.gnu.org/licenses/
14
15// Official git repository and contact information can be found at
16// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18#pragma once
19
20// TODO: Remove the Windows-specific code, FILE is fine there too.
21
22#include <map>
23
24#include "core/file_sys/file_sys.h"
25
26#ifdef _WIN32
27typedef void * HANDLE;
28#endif
29
30#if defined(__APPLE__)
31
32#if TARGET_OS_IPHONE
33#define HOST_IS_CASE_SENSITIVE 1
34#elif TARGET_IPHONE_SIMULATOR
35#define HOST_IS_CASE_SENSITIVE 0
36#else
37// Mac OSX case sensitivity defaults off, but is user configurable (when
38// creating a filesytem), so assume the worst:
39#define HOST_IS_CASE_SENSITIVE 1
40#endif
41
42#elif defined(_WIN32) || defined(__SYMBIAN32__)
43#define HOST_IS_CASE_SENSITIVE 0
44
45#else // Android, Linux, BSD (and the rest?)
46#define HOST_IS_CASE_SENSITIVE 1
47
48#endif
49
50#if HOST_IS_CASE_SENSITIVE
51enum FixPathCaseBehavior {
52 FPC_FILE_MUST_EXIST, // all path components must exist (rmdir, move from)
53 FPC_PATH_MUST_EXIST, // all except the last one must exist - still tries to fix last one (fopen, move to)
54 FPC_PARTIAL_ALLOWED, // don't care how many exist (mkdir recursive)
55};
56
57bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior);
58#endif
59
60struct DirectoryFileHandle
61{
62#ifdef _WIN32
63 HANDLE hFile;
64#else
65 FILE* hFile;
66#endif
67 DirectoryFileHandle()
68 {
69#ifdef _WIN32
70 hFile = (HANDLE)-1;
71#else
72 hFile = 0;
73#endif
74 }
75
76 std::string GetLocalPath(std::string& basePath, std::string localpath);
77 bool Open(std::string& basePath, std::string& fileName, FileAccess access);
78 size_t Read(u8* pointer, s64 size);
79 size_t Write(const u8* pointer, s64 size);
80 size_t Seek(s32 position, FileMove type);
81 void Close();
82};
83
84class DirectoryFileSystem : public IFileSystem {
85public:
86 DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath);
87 ~DirectoryFileSystem();
88
89 void DoState(PointerWrap &p);
90 std::vector<FileInfo> GetDirListing(std::string path);
91 u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL);
92 void CloseFile(u32 handle);
93 size_t ReadFile(u32 handle, u8 *pointer, s64 size);
94 size_t WriteFile(u32 handle, const u8 *pointer, s64 size);
95 size_t SeekFile(u32 handle, s32 position, FileMove type);
96 FileInfo GetFileInfo(std::string filename);
97 bool OwnsHandle(u32 handle);
98
99 bool MkDir(const std::string &dirname);
100 bool RmDir(const std::string &dirname);
101 int RenameFile(const std::string &from, const std::string &to);
102 bool RemoveFile(const std::string &filename);
103 bool GetHostPath(const std::string &inpath, std::string &outpath);
104
105private:
106 struct OpenFileEntry {
107 DirectoryFileHandle hFile;
108 };
109
110 typedef std::map<u32, OpenFileEntry> EntryMap;
111 EntryMap entries;
112 std::string basePath;
113 IHandleAllocator *hAlloc;
114
115 // In case of Windows: Translate slashes, etc.
116 std::string GetLocalPath(std::string localpath);
117};
118
119// VFSFileSystem: Ability to map in Android APK paths as well! Does not support all features, only meant for fonts.
120// Very inefficient - always load the whole file on open.
121class VFSFileSystem : public IFileSystem {
122public:
123 VFSFileSystem(IHandleAllocator *_hAlloc, std::string _basePath);
124 ~VFSFileSystem();
125
126 void DoState(PointerWrap &p);
127 std::vector<FileInfo> GetDirListing(std::string path);
128 u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL);
129 void CloseFile(u32 handle);
130 size_t ReadFile(u32 handle, u8 *pointer, s64 size);
131 size_t WriteFile(u32 handle, const u8 *pointer, s64 size);
132 size_t SeekFile(u32 handle, s32 position, FileMove type);
133 FileInfo GetFileInfo(std::string filename);
134 bool OwnsHandle(u32 handle);
135
136 bool MkDir(const std::string &dirname);
137 bool RmDir(const std::string &dirname);
138 int RenameFile(const std::string &from, const std::string &to);
139 bool RemoveFile(const std::string &filename);
140 bool GetHostPath(const std::string &inpath, std::string &outpath);
141
142private:
143 struct OpenFileEntry {
144 u8 *fileData;
145 size_t size;
146 size_t seekPos;
147 };
148
149 typedef std::map<u32, OpenFileEntry> EntryMap;
150 EntryMap entries;
151 std::string basePath;
152 IHandleAllocator *hAlloc;
153
154 std::string GetLocalPath(std::string localpath);
155};
diff --git a/src/core/file_sys/meta_file_system.cpp b/src/core/file_sys/meta_file_system.cpp
deleted file mode 100644
index 4347ff451..000000000
--- a/src/core/file_sys/meta_file_system.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
1// Copyright (c) 2012- PPSSPP Project.
2
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, version 2.0 or later versions.
6
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU General Public License 2.0 for more details.
11
12// A copy of the GPL 2.0 should have been included with the program.
13// If not, see http://www.gnu.org/licenses/
14
15// Official git repository and contact information can be found at
16// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18#include <set>
19#include <algorithm>
20
21#include "common/string_util.h"
22#include "core/file_sys/meta_file_system.h"
23
24static bool ApplyPathStringToComponentsVector(std::vector<std::string> &vector, const std::string &pathString)
25{
26 size_t len = pathString.length();
27 size_t start = 0;
28
29 while (start < len)
30 {
31 size_t i = pathString.find('/', start);
32 if (i == std::string::npos)
33 i = len;
34
35 if (i > start)
36 {
37 std::string component = pathString.substr(start, i - start);
38 if (component != ".")
39 {
40 if (component == "..")
41 {
42 if (vector.size() != 0)
43 {
44 vector.pop_back();
45 }
46 else
47 {
48 // The PSP silently ignores attempts to .. to parent of root directory
49 WARN_LOG(FILESYS, "RealPath: ignoring .. beyond root - root directory is its own parent: \"%s\"", pathString.c_str());
50 }
51 }
52 else
53 {
54 vector.push_back(component);
55 }
56 }
57 }
58
59 start = i + 1;
60 }
61
62 return true;
63}
64
65/*
66 * Changes relative paths to absolute, removes ".", "..", and trailing "/"
67 * "drive:./blah" is absolute (ignore the dot) and "/blah" is relative (because it's missing "drive:")
68 * babel (and possibly other games) use "/directoryThatDoesNotExist/../directoryThatExists/filename"
69 */
70static bool RealPath(const std::string &currentDirectory, const std::string &inPath, std::string &outPath)
71{
72 size_t inLen = inPath.length();
73 if (inLen == 0)
74 {
75 WARN_LOG(FILESYS, "RealPath: inPath is empty");
76 outPath = currentDirectory;
77 return true;
78 }
79
80 size_t inColon = inPath.find(':');
81 if (inColon + 1 == inLen)
82 {
83 // There's nothing after the colon, e.g. umd0: - this is perfectly valid.
84 outPath = inPath;
85 return true;
86 }
87
88 bool relative = (inColon == std::string::npos);
89
90 std::string prefix, inAfterColon;
91 std::vector<std::string> cmpnts; // path components
92 size_t outPathCapacityGuess = inPath.length();
93
94 if (relative)
95 {
96 size_t curDirLen = currentDirectory.length();
97 if (curDirLen == 0)
98 {
99 ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory is empty", inPath.c_str());
100 return false;
101 }
102
103 size_t curDirColon = currentDirectory.find(':');
104 if (curDirColon == std::string::npos)
105 {
106 ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" has no prefix", inPath.c_str(), currentDirectory.c_str());
107 return false;
108 }
109 if (curDirColon + 1 == curDirLen)
110 {
111 ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" is all prefix and no path. Using \"/\" as path for current directory.", inPath.c_str(), currentDirectory.c_str());
112 }
113 else
114 {
115 const std::string curDirAfter = currentDirectory.substr(curDirColon + 1);
116 if (! ApplyPathStringToComponentsVector(cmpnts, curDirAfter) )
117 {
118 ERROR_LOG(FILESYS,"RealPath: currentDirectory is not a valid path: \"%s\"", currentDirectory.c_str());
119 return false;
120 }
121
122 outPathCapacityGuess += curDirLen;
123 }
124
125 prefix = currentDirectory.substr(0, curDirColon + 1);
126 inAfterColon = inPath;
127 }
128 else
129 {
130 prefix = inPath.substr(0, inColon + 1);
131 inAfterColon = inPath.substr(inColon + 1);
132 }
133
134 // Special case: "disc0:" is different from "disc0:/", so keep track of the single slash.
135 if (inAfterColon == "/")
136 {
137 outPath = prefix + inAfterColon;
138 return true;
139 }
140
141 if (! ApplyPathStringToComponentsVector(cmpnts, inAfterColon) )
142 {
143 WARN_LOG(FILESYS, "RealPath: inPath is not a valid path: \"%s\"", inPath.c_str());
144 return false;
145 }
146
147 outPath.clear();
148 outPath.reserve(outPathCapacityGuess);
149
150 outPath.append(prefix);
151
152 size_t numCmpnts = cmpnts.size();
153 for (size_t i = 0; i < numCmpnts; i++)
154 {
155 outPath.append(1, '/');
156 outPath.append(cmpnts[i]);
157 }
158
159 return true;
160}
161
162IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle)
163{
164 std::lock_guard<std::recursive_mutex> guard(lock);
165 for (size_t i = 0; i < fileSystems.size(); i++)
166 {
167 if (fileSystems[i].system->OwnsHandle(handle))
168 return fileSystems[i].system; //got it!
169 }
170 //none found?
171 return 0;
172}
173
174bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath, MountPoint **system)
175{
176 std::lock_guard<std::recursive_mutex> guard(lock);
177 std::string realpath;
178
179 // Special handling: host0:command.txt (as seen in Super Monkey Ball Adventures, for example)
180 // appears to mean the current directory on the UMD. Let's just assume the current directory.
181 std::string inpath = _inpath;
182 if (strncasecmp(inpath.c_str(), "host0:", strlen("host0:")) == 0) {
183 INFO_LOG(FILESYS, "Host0 path detected, stripping: %s", inpath.c_str());
184 inpath = inpath.substr(strlen("host0:"));
185 }
186
187 const std::string *currentDirectory = &startingDirectory;
188
189 _assert_msg_(FILESYS, false, "must implement equiv of __KernelGetCurThread");
190
191 int currentThread = 0;//__KernelGetCurThread();
192 currentDir_t::iterator it = currentDir.find(currentThread);
193 if (it == currentDir.end())
194 {
195 //Attempt to emulate SCE_KERNEL_ERROR_NOCWD / 8002032C: may break things requiring fixes elsewhere
196 if (inpath.find(':') == std::string::npos /* means path is relative */)
197 {
198 lastOpenError = -1;//SCE_KERNEL_ERROR_NOCWD;
199 WARN_LOG(FILESYS, "Path is relative, but current directory not set for thread %i. returning 8002032C(SCE_KERNEL_ERROR_NOCWD) instead.", currentThread);
200 }
201 }
202 else
203 {
204 currentDirectory = &(it->second);
205 }
206
207 if ( RealPath(*currentDirectory, inpath, realpath) )
208 {
209 for (size_t i = 0; i < fileSystems.size(); i++)
210 {
211 size_t prefLen = fileSystems[i].prefix.size();
212 if (strncasecmp(fileSystems[i].prefix.c_str(), realpath.c_str(), prefLen) == 0)
213 {
214 outpath = realpath.substr(prefLen);
215 *system = &(fileSystems[i]);
216
217 INFO_LOG(FILESYS, "MapFilePath: mapped \"%s\" to prefix: \"%s\", path: \"%s\"", inpath.c_str(), fileSystems[i].prefix.c_str(), outpath.c_str());
218
219 return true;
220 }
221 }
222 }
223
224 DEBUG_LOG(FILESYS, "MapFilePath: failed mapping \"%s\", returning false", inpath.c_str());
225 return false;
226}
227
228void MetaFileSystem::Mount(std::string prefix, IFileSystem *system)
229{
230 std::lock_guard<std::recursive_mutex> guard(lock);
231 MountPoint x;
232 x.prefix = prefix;
233 x.system = system;
234 fileSystems.push_back(x);
235}
236
237void MetaFileSystem::Unmount(std::string prefix, IFileSystem *system)
238{
239 std::lock_guard<std::recursive_mutex> guard(lock);
240 MountPoint x;
241 x.prefix = prefix;
242 x.system = system;
243 fileSystems.erase(std::remove(fileSystems.begin(), fileSystems.end(), x), fileSystems.end());
244}
245
246void MetaFileSystem::Shutdown()
247{
248 std::lock_guard<std::recursive_mutex> guard(lock);
249 current = 6;
250
251 // Ownership is a bit convoluted. Let's just delete everything once.
252
253 std::set<IFileSystem *> toDelete;
254 for (size_t i = 0; i < fileSystems.size(); i++) {
255 toDelete.insert(fileSystems[i].system);
256 }
257
258 for (auto iter = toDelete.begin(); iter != toDelete.end(); ++iter)
259 {
260 delete *iter;
261 }
262
263 fileSystems.clear();
264 currentDir.clear();
265 startingDirectory = "";
266}
267
268u32 MetaFileSystem::OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename)
269{
270 std::lock_guard<std::recursive_mutex> guard(lock);
271 u32 h = OpenFile(filename, access, devicename);
272 error = lastOpenError;
273 return h;
274}
275
276u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename)
277{
278 std::lock_guard<std::recursive_mutex> guard(lock);
279 lastOpenError = 0;
280 std::string of;
281 MountPoint *mount;
282 if (MapFilePath(filename, of, &mount))
283 {
284 return mount->system->OpenFile(of, access, mount->prefix.c_str());
285 }
286 else
287 {
288 return 0;
289 }
290}
291
292FileInfo MetaFileSystem::GetFileInfo(std::string filename)
293{
294 std::lock_guard<std::recursive_mutex> guard(lock);
295 std::string of;
296 IFileSystem *system;
297 if (MapFilePath(filename, of, &system))
298 {
299 return system->GetFileInfo(of);
300 }
301 else
302 {
303 FileInfo bogus; // TODO
304 return bogus;
305 }
306}
307
308bool MetaFileSystem::GetHostPath(const std::string &inpath, std::string &outpath)
309{
310 std::lock_guard<std::recursive_mutex> guard(lock);
311 std::string of;
312 IFileSystem *system;
313 if (MapFilePath(inpath, of, &system)) {
314 return system->GetHostPath(of, outpath);
315 } else {
316 return false;
317 }
318}
319
320std::vector<FileInfo> MetaFileSystem::GetDirListing(std::string path)
321{
322 std::lock_guard<std::recursive_mutex> guard(lock);
323 std::string of;
324 IFileSystem *system;
325 if (MapFilePath(path, of, &system))
326 {
327 return system->GetDirListing(of);
328 }
329 else
330 {
331 std::vector<FileInfo> empty;
332 return empty;
333 }
334}
335
336void MetaFileSystem::ThreadEnded(int threadID)
337{
338 std::lock_guard<std::recursive_mutex> guard(lock);
339 currentDir.erase(threadID);
340}
341
342int MetaFileSystem::ChDir(const std::string &dir)
343{
344 std::lock_guard<std::recursive_mutex> guard(lock);
345 // Retain the old path and fail if the arg is 1023 bytes or longer.
346 if (dir.size() >= 1023)
347 return -1;//SCE_KERNEL_ERROR_NAMETOOLONG;
348
349 _assert_msg_(FILESYS, false, "must implement equiv of __KernelGetCurThread");
350
351 int curThread = 0; //__KernelGetCurThread();
352
353 std::string of;
354 MountPoint *mountPoint;
355 if (MapFilePath(dir, of, &mountPoint))
356 {
357 currentDir[curThread] = mountPoint->prefix + of;
358 return 0;
359 }
360 else
361 {
362 for (size_t i = 0; i < fileSystems.size(); i++)
363 {
364 const std::string &prefix = fileSystems[i].prefix;
365 if (strncasecmp(prefix.c_str(), dir.c_str(), prefix.size()) == 0)
366 {
367 // The PSP is completely happy with invalid current dirs as long as they have a valid device.
368 WARN_LOG(FILESYS, "ChDir failed to map path \"%s\", saving as current directory anyway", dir.c_str());
369 currentDir[curThread] = dir;
370 return 0;
371 }
372 }
373
374 WARN_LOG(FILESYS, "ChDir failed to map device for \"%s\", failing", dir.c_str());
375 return -1;//SCE_KERNEL_ERROR_NODEV;
376 }
377}
378
379bool MetaFileSystem::MkDir(const std::string &dirname)
380{
381 std::lock_guard<std::recursive_mutex> guard(lock);
382 std::string of;
383 IFileSystem *system;
384 if (MapFilePath(dirname, of, &system))
385 {
386 return system->MkDir(of);
387 }
388 else
389 {
390 return false;
391 }
392}
393
394bool MetaFileSystem::RmDir(const std::string &dirname)
395{
396 std::lock_guard<std::recursive_mutex> guard(lock);
397 std::string of;
398 IFileSystem *system;
399 if (MapFilePath(dirname, of, &system))
400 {
401 return system->RmDir(of);
402 }
403 else
404 {
405 return false;
406 }
407}
408
409int MetaFileSystem::RenameFile(const std::string &from, const std::string &to)
410{
411 std::lock_guard<std::recursive_mutex> guard(lock);
412 std::string of;
413 std::string rf;
414 IFileSystem *osystem;
415 IFileSystem *rsystem = NULL;
416 if (MapFilePath(from, of, &osystem))
417 {
418 // If it's a relative path, it seems to always use from's filesystem.
419 if (to.find(":/") != to.npos)
420 {
421 if (!MapFilePath(to, rf, &rsystem))
422 return -1;
423 }
424 else
425 {
426 rf = to;
427 rsystem = osystem;
428 }
429
430 if (osystem != rsystem)
431 return -1;//SCE_KERNEL_ERROR_XDEV;
432
433 return osystem->RenameFile(of, rf);
434 }
435 else
436 {
437 return -1;
438 }
439}
440
441bool MetaFileSystem::RemoveFile(const std::string &filename)
442{
443 std::lock_guard<std::recursive_mutex> guard(lock);
444 std::string of;
445 IFileSystem *system;
446 if (MapFilePath(filename, of, &system))
447 {
448 return system->RemoveFile(of);
449 }
450 else
451 {
452 return false;
453 }
454}
455
456void MetaFileSystem::CloseFile(u32 handle)
457{
458 std::lock_guard<std::recursive_mutex> guard(lock);
459 IFileSystem *sys = GetHandleOwner(handle);
460 if (sys)
461 sys->CloseFile(handle);
462}
463
464size_t MetaFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size)
465{
466 std::lock_guard<std::recursive_mutex> guard(lock);
467 IFileSystem *sys = GetHandleOwner(handle);
468 if (sys)
469 return sys->ReadFile(handle,pointer,size);
470 else
471 return 0;
472}
473
474size_t MetaFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)
475{
476 std::lock_guard<std::recursive_mutex> guard(lock);
477 IFileSystem *sys = GetHandleOwner(handle);
478 if (sys)
479 return sys->WriteFile(handle,pointer,size);
480 else
481 return 0;
482}
483
484size_t MetaFileSystem::SeekFile(u32 handle, s32 position, FileMove type)
485{
486 std::lock_guard<std::recursive_mutex> guard(lock);
487 IFileSystem *sys = GetHandleOwner(handle);
488 if (sys)
489 return sys->SeekFile(handle,position,type);
490 else
491 return 0;
492}
493
494void MetaFileSystem::DoState(PointerWrap &p)
495{
496 std::lock_guard<std::recursive_mutex> guard(lock);
497
498 auto s = p.Section("MetaFileSystem", 1);
499 if (!s)
500 return;
501
502 p.Do(current);
503
504 // Save/load per-thread current directory map
505 p.Do(currentDir);
506
507 u32 n = (u32) fileSystems.size();
508 p.Do(n);
509 if (n != (u32) fileSystems.size())
510 {
511 p.SetError(p.ERROR_FAILURE);
512 ERROR_LOG(FILESYS, "Savestate failure: number of filesystems doesn't match.");
513 return;
514 }
515
516 for (u32 i = 0; i < n; ++i)
517 fileSystems[i].system->DoState(p);
518}
519
diff --git a/src/core/file_sys/meta_file_system.h b/src/core/file_sys/meta_file_system.h
deleted file mode 100644
index f358d8d5c..000000000
--- a/src/core/file_sys/meta_file_system.h
+++ /dev/null
@@ -1,110 +0,0 @@
1// Copyright (c) 2012- PPSSPP Project.
2
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, version 2.0 or later versions.
6
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU General Public License 2.0 for more details.
11
12// A copy of the GPL 2.0 should have been included with the program.
13// If not, see http://www.gnu.org/licenses/
14
15// Official git repository and contact information can be found at
16// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18#pragma once
19
20#include "common/std_mutex.h"
21
22#include "core/file_sys/file_sys.h"
23
24class MetaFileSystem : public IHandleAllocator, public IFileSystem
25{
26private:
27 u32 current;
28 struct MountPoint
29 {
30 std::string prefix;
31 IFileSystem *system;
32
33 bool operator == (const MountPoint &other) const
34 {
35 return prefix == other.prefix && system == other.system;
36 }
37 };
38 std::vector<MountPoint> fileSystems;
39
40 typedef std::map<int, std::string> currentDir_t;
41 currentDir_t currentDir;
42
43 std::string startingDirectory;
44 int lastOpenError;
45 std::recursive_mutex lock;
46
47public:
48 MetaFileSystem()
49 {
50 current = 6; // what?
51 }
52
53 void Mount(std::string prefix, IFileSystem *system);
54 void Unmount(std::string prefix, IFileSystem *system);
55
56 void ThreadEnded(int threadID);
57
58 void Shutdown();
59
60 u32 GetNewHandle() {return current++;}
61 void FreeHandle(u32 handle) {}
62
63 virtual void DoState(PointerWrap &p);
64
65 IFileSystem *GetHandleOwner(u32 handle);
66 bool MapFilePath(const std::string &inpath, std::string &outpath, MountPoint **system);
67
68 inline bool MapFilePath(const std::string &_inpath, std::string &outpath, IFileSystem **system)
69 {
70 MountPoint *mountPoint;
71 if (MapFilePath(_inpath, outpath, &mountPoint))
72 {
73 *system = mountPoint->system;
74 return true;
75 }
76
77 return false;
78 }
79
80 // Only possible if a file system is a DirectoryFileSystem or similar.
81 bool GetHostPath(const std::string &inpath, std::string &outpath);
82
83 std::vector<FileInfo> GetDirListing(std::string path);
84 u32 OpenFile(std::string filename, FileAccess access, const char *devicename = NULL);
85 u32 OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename = NULL);
86 void CloseFile(u32 handle);
87 size_t ReadFile(u32 handle, u8 *pointer, s64 size);
88 size_t WriteFile(u32 handle, const u8 *pointer, s64 size);
89 size_t SeekFile(u32 handle, s32 position, FileMove type);
90 FileInfo GetFileInfo(std::string filename);
91 bool OwnsHandle(u32 handle) {return false;}
92 inline size_t GetSeekPos(u32 handle)
93 {
94 return SeekFile(handle, 0, FILEMOVE_CURRENT);
95 }
96
97 virtual int ChDir(const std::string &dir);
98
99 virtual bool MkDir(const std::string &dirname);
100 virtual bool RmDir(const std::string &dirname);
101 virtual int RenameFile(const std::string &from, const std::string &to);
102 virtual bool RemoveFile(const std::string &filename);
103
104 // TODO: void IoCtl(...)
105
106 void SetStartingDirectory(const std::string &dir) {
107 std::lock_guard<std::recursive_mutex> guard(lock);
108 startingDirectory = dir;
109 }
110};
diff --git a/src/core/system.cpp b/src/core/system.cpp
index 9b1e96888..43d0eef2c 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -15,7 +15,6 @@
15namespace System { 15namespace System {
16 16
17volatile State g_state; 17volatile State g_state;
18MetaFileSystem g_ctr_file_system;
19 18
20void UpdateState(State state) { 19void UpdateState(State state) {
21} 20}
@@ -45,7 +44,6 @@ void Shutdown() {
45 CoreTiming::Shutdown(); 44 CoreTiming::Shutdown();
46 VideoCore::Shutdown(); 45 VideoCore::Shutdown();
47 Kernel::Shutdown(); 46 Kernel::Shutdown();
48 g_ctr_file_system.Shutdown();
49} 47}
50 48
51} // namespace 49} // namespace
diff --git a/src/core/system.h b/src/core/system.h
index 09f1f6ebe..8f8ddf87b 100644
--- a/src/core/system.h
+++ b/src/core/system.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include "common/emu_window.h" 7#include "common/emu_window.h"
8#include "core/file_sys/meta_file_system.h"
9 8
10//////////////////////////////////////////////////////////////////////////////////////////////////// 9////////////////////////////////////////////////////////////////////////////////////////////////////
11 10
@@ -24,7 +23,6 @@ typedef enum {
24} State; 23} State;
25 24
26extern volatile State g_state; 25extern volatile State g_state;
27extern MetaFileSystem g_ctr_file_system;
28 26
29void UpdateState(State state); 27void UpdateState(State state);
30void Init(EmuWindow* emu_window); 28void Init(EmuWindow* emu_window);