summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ShizZy2013-09-25 21:25:46 -0400
committerGravatar ShizZy2013-09-25 21:25:46 -0400
commita7b06698ff012aa7b1094414e796ffae1ca1eb4d (patch)
tree8ff0d73079c33b8068c086ebaf9a7f07a8762aa5 /src
parentrenamed file_sys_directory.* to directory_file_system.* (diff)
downloadyuzu-a7b06698ff012aa7b1094414e796ffae1ca1eb4d.tar.gz
yuzu-a7b06698ff012aa7b1094414e796ffae1ca1eb4d.tar.xz
yuzu-a7b06698ff012aa7b1094414e796ffae1ca1eb4d.zip
added meta_file_system to project
Diffstat (limited to 'src')
-rw-r--r--src/core/core.vcxproj2
-rw-r--r--src/core/core.vcxproj.filters6
-rw-r--r--src/core/src/file_sys/meta_file_system.cpp520
-rw-r--r--src/core/src/file_sys/meta_file_system.h109
4 files changed, 637 insertions, 0 deletions
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index 7d7dceee3..c771f2e2d 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -138,6 +138,7 @@
138 <ClCompile Include="src\arm\disassembler\arm_disasm.cpp" /> 138 <ClCompile Include="src\arm\disassembler\arm_disasm.cpp" />
139 <ClCompile Include="src\core.cpp" /> 139 <ClCompile Include="src\core.cpp" />
140 <ClCompile Include="src\file_sys\directory_file_system.cpp" /> 140 <ClCompile Include="src\file_sys\directory_file_system.cpp" />
141 <ClCompile Include="src\file_sys\meta_file_system.cpp" />
141 <ClCompile Include="src\loader.cpp" /> 142 <ClCompile Include="src\loader.cpp" />
142 <ClCompile Include="src\mem_map.cpp" /> 143 <ClCompile Include="src\mem_map.cpp" />
143 <ClCompile Include="src\mem_map_funcs.cpp" /> 144 <ClCompile Include="src\mem_map_funcs.cpp" />
@@ -159,6 +160,7 @@
159 <ClInclude Include="src\core.h" /> 160 <ClInclude Include="src\core.h" />
160 <ClInclude Include="src\file_sys\directory_file_system.h" /> 161 <ClInclude Include="src\file_sys\directory_file_system.h" />
161 <ClInclude Include="src\file_sys\file_sys.h" /> 162 <ClInclude Include="src\file_sys\file_sys.h" />
163 <ClInclude Include="src\file_sys\meta_file_system.h" />
162 <ClInclude Include="src\loader.h" /> 164 <ClInclude Include="src\loader.h" />
163 <ClInclude Include="src\mem_map.h" /> 165 <ClInclude Include="src\mem_map.h" />
164 </ItemGroup> 166 </ItemGroup>
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index 93becd9d7..f75e6305c 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -17,6 +17,9 @@
17 <ClCompile Include="src\file_sys\directory_file_system.cpp"> 17 <ClCompile Include="src\file_sys\directory_file_system.cpp">
18 <Filter>file_sys</Filter> 18 <Filter>file_sys</Filter>
19 </ClCompile> 19 </ClCompile>
20 <ClCompile Include="src\file_sys\meta_file_system.cpp">
21 <Filter>file_sys</Filter>
22 </ClCompile>
20 </ItemGroup> 23 </ItemGroup>
21 <ItemGroup> 24 <ItemGroup>
22 <Filter Include="arm"> 25 <Filter Include="arm">
@@ -81,6 +84,9 @@
81 <ClInclude Include="src\file_sys\directory_file_system.h"> 84 <ClInclude Include="src\file_sys\directory_file_system.h">
82 <Filter>file_sys</Filter> 85 <Filter>file_sys</Filter>
83 </ClInclude> 86 </ClInclude>
87 <ClInclude Include="src\file_sys\meta_file_system.h">
88 <Filter>file_sys</Filter>
89 </ClInclude>
84 </ItemGroup> 90 </ItemGroup>
85 <ItemGroup> 91 <ItemGroup>
86 <None Include="CMakeLists.txt" /> 92 <None Include="CMakeLists.txt" />
diff --git a/src/core/src/file_sys/meta_file_system.cpp b/src/core/src/file_sys/meta_file_system.cpp
new file mode 100644
index 000000000..f86c3cb18
--- /dev/null
+++ b/src/core/src/file_sys/meta_file_system.cpp
@@ -0,0 +1,520 @@
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#include "string_util.h"
21#include "file_sys/meta_file_system.h"
22//#include "Core/HLE/sceKernelThread.h"
23//#include "Core/Reporting.h"
24
25static bool ApplyPathStringToComponentsVector(std::vector<std::string> &vector, const std::string &pathString)
26{
27 size_t len = pathString.length();
28 size_t start = 0;
29
30 while (start < len)
31 {
32 size_t i = pathString.find('/', start);
33 if (i == std::string::npos)
34 i = len;
35
36 if (i > start)
37 {
38 std::string component = pathString.substr(start, i - start);
39 if (component != ".")
40 {
41 if (component == "..")
42 {
43 if (vector.size() != 0)
44 {
45 vector.pop_back();
46 }
47 else
48 {
49 // The PSP silently ignores attempts to .. to parent of root directory
50 WARN_LOG(FILESYS, "RealPath: ignoring .. beyond root - root directory is its own parent: \"%s\"", pathString.c_str());
51 }
52 }
53 else
54 {
55 vector.push_back(component);
56 }
57 }
58 }
59
60 start = i + 1;
61 }
62
63 return true;
64}
65
66/*
67 * Changes relative paths to absolute, removes ".", "..", and trailing "/"
68 * "drive:./blah" is absolute (ignore the dot) and "/blah" is relative (because it's missing "drive:")
69 * babel (and possibly other games) use "/directoryThatDoesNotExist/../directoryThatExists/filename"
70 */
71static bool RealPath(const std::string &currentDirectory, const std::string &inPath, std::string &outPath)
72{
73 size_t inLen = inPath.length();
74 if (inLen == 0)
75 {
76 WARN_LOG(FILESYS, "RealPath: inPath is empty");
77 outPath = currentDirectory;
78 return true;
79 }
80
81 size_t inColon = inPath.find(':');
82 if (inColon + 1 == inLen)
83 {
84 // There's nothing after the colon, e.g. umd0: - this is perfectly valid.
85 outPath = inPath;
86 return true;
87 }
88
89 bool relative = (inColon == std::string::npos);
90
91 std::string prefix, inAfterColon;
92 std::vector<std::string> cmpnts; // path components
93 size_t outPathCapacityGuess = inPath.length();
94
95 if (relative)
96 {
97 size_t curDirLen = currentDirectory.length();
98 if (curDirLen == 0)
99 {
100 ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory is empty", inPath.c_str());
101 return false;
102 }
103
104 size_t curDirColon = currentDirectory.find(':');
105 if (curDirColon == std::string::npos)
106 {
107 ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" has no prefix", inPath.c_str(), currentDirectory.c_str());
108 return false;
109 }
110 if (curDirColon + 1 == curDirLen)
111 {
112 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());
113 }
114 else
115 {
116 const std::string curDirAfter = currentDirectory.substr(curDirColon + 1);
117 if (! ApplyPathStringToComponentsVector(cmpnts, curDirAfter) )
118 {
119 ERROR_LOG(FILESYS,"RealPath: currentDirectory is not a valid path: \"%s\"", currentDirectory.c_str());
120 return false;
121 }
122
123 outPathCapacityGuess += curDirLen;
124 }
125
126 prefix = currentDirectory.substr(0, curDirColon + 1);
127 inAfterColon = inPath;
128 }
129 else
130 {
131 prefix = inPath.substr(0, inColon + 1);
132 inAfterColon = inPath.substr(inColon + 1);
133 }
134
135 // Special case: "disc0:" is different from "disc0:/", so keep track of the single slash.
136 if (inAfterColon == "/")
137 {
138 outPath = prefix + inAfterColon;
139 return true;
140 }
141
142 if (! ApplyPathStringToComponentsVector(cmpnts, inAfterColon) )
143 {
144 WARN_LOG(FILESYS, "RealPath: inPath is not a valid path: \"%s\"", inPath.c_str());
145 return false;
146 }
147
148 outPath.clear();
149 outPath.reserve(outPathCapacityGuess);
150
151 outPath.append(prefix);
152
153 size_t numCmpnts = cmpnts.size();
154 for (size_t i = 0; i < numCmpnts; i++)
155 {
156 outPath.append(1, '/');
157 outPath.append(cmpnts[i]);
158 }
159
160 return true;
161}
162
163IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle)
164{
165 std::lock_guard<std::mutex> guard(lock);
166 for (size_t i = 0; i < fileSystems.size(); i++)
167 {
168 if (fileSystems[i].system->OwnsHandle(handle))
169 return fileSystems[i].system; //got it!
170 }
171 //none found?
172 return 0;
173}
174
175bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath, MountPoint **system)
176{
177 std::lock_guard<std::mutex> guard(lock);
178 std::string realpath;
179
180 // Special handling: host0:command.txt (as seen in Super Monkey Ball Adventures, for example)
181 // appears to mean the current directory on the UMD. Let's just assume the current directory.
182 std::string inpath = _inpath;
183 if (strncasecmp(inpath.c_str(), "host0:", strlen("host0:")) == 0) {
184 INFO_LOG(FILESYS, "Host0 path detected, stripping: %s", inpath.c_str());
185 inpath = inpath.substr(strlen("host0:"));
186 }
187
188 const std::string *currentDirectory = &startingDirectory;
189
190 _assert_msg_(FILESYS, false, "must implement equiv of __KernelGetCurThread");
191
192 int currentThread = 0;//__KernelGetCurThread();
193 currentDir_t::iterator it = currentDir.find(currentThread);
194 if (it == currentDir.end())
195 {
196 //Attempt to emulate SCE_KERNEL_ERROR_NOCWD / 8002032C: may break things requiring fixes elsewhere
197 if (inpath.find(':') == std::string::npos /* means path is relative */)
198 {
199 lastOpenError = -1;//SCE_KERNEL_ERROR_NOCWD;
200 WARN_LOG(FILESYS, "Path is relative, but current directory not set for thread %i. returning 8002032C(SCE_KERNEL_ERROR_NOCWD) instead.", currentThread);
201 }
202 }
203 else
204 {
205 currentDirectory = &(it->second);
206 }
207
208 if ( RealPath(*currentDirectory, inpath, realpath) )
209 {
210 for (size_t i = 0; i < fileSystems.size(); i++)
211 {
212 size_t prefLen = fileSystems[i].prefix.size();
213 if (strncasecmp(fileSystems[i].prefix.c_str(), realpath.c_str(), prefLen) == 0)
214 {
215 outpath = realpath.substr(prefLen);
216 *system = &(fileSystems[i]);
217
218 INFO_LOG(FILESYS, "MapFilePath: mapped \"%s\" to prefix: \"%s\", path: \"%s\"", inpath.c_str(), fileSystems[i].prefix.c_str(), outpath.c_str());
219
220 return true;
221 }
222 }
223 }
224
225 DEBUG_LOG(FILESYS, "MapFilePath: failed mapping \"%s\", returning false", inpath.c_str());
226 return false;
227}
228
229void MetaFileSystem::Mount(std::string prefix, IFileSystem *system)
230{
231 std::lock_guard<std::mutex> guard(lock);
232 MountPoint x;
233 x.prefix = prefix;
234 x.system = system;
235 fileSystems.push_back(x);
236}
237
238void MetaFileSystem::Unmount(std::string prefix, IFileSystem *system)
239{
240 std::lock_guard<std::mutex> guard(lock);
241 MountPoint x;
242 x.prefix = prefix;
243 x.system = system;
244 fileSystems.erase(std::remove(fileSystems.begin(), fileSystems.end(), x), fileSystems.end());
245}
246
247void MetaFileSystem::Shutdown()
248{
249 std::lock_guard<std::mutex> guard(lock);
250 current = 6;
251
252 // Ownership is a bit convoluted. Let's just delete everything once.
253
254 std::set<IFileSystem *> toDelete;
255 for (size_t i = 0; i < fileSystems.size(); i++) {
256 toDelete.insert(fileSystems[i].system);
257 }
258
259 for (auto iter = toDelete.begin(); iter != toDelete.end(); ++iter)
260 {
261 delete *iter;
262 }
263
264 fileSystems.clear();
265 currentDir.clear();
266 startingDirectory = "";
267}
268
269u32 MetaFileSystem::OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename)
270{
271 std::lock_guard<std::mutex> guard(lock);
272 u32 h = OpenFile(filename, access, devicename);
273 error = lastOpenError;
274 return h;
275}
276
277u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename)
278{
279 std::lock_guard<std::mutex> guard(lock);
280 lastOpenError = 0;
281 std::string of;
282 MountPoint *mount;
283 if (MapFilePath(filename, of, &mount))
284 {
285 return mount->system->OpenFile(of, access, mount->prefix.c_str());
286 }
287 else
288 {
289 return 0;
290 }
291}
292
293FileInfo MetaFileSystem::GetFileInfo(std::string filename)
294{
295 std::lock_guard<std::mutex> guard(lock);
296 std::string of;
297 IFileSystem *system;
298 if (MapFilePath(filename, of, &system))
299 {
300 return system->GetFileInfo(of);
301 }
302 else
303 {
304 FileInfo bogus; // TODO
305 return bogus;
306 }
307}
308
309bool MetaFileSystem::GetHostPath(const std::string &inpath, std::string &outpath)
310{
311 std::lock_guard<std::mutex> guard(lock);
312 std::string of;
313 IFileSystem *system;
314 if (MapFilePath(inpath, of, &system)) {
315 return system->GetHostPath(of, outpath);
316 } else {
317 return false;
318 }
319}
320
321std::vector<FileInfo> MetaFileSystem::GetDirListing(std::string path)
322{
323 std::lock_guard<std::mutex> guard(lock);
324 std::string of;
325 IFileSystem *system;
326 if (MapFilePath(path, of, &system))
327 {
328 return system->GetDirListing(of);
329 }
330 else
331 {
332 std::vector<FileInfo> empty;
333 return empty;
334 }
335}
336
337void MetaFileSystem::ThreadEnded(int threadID)
338{
339 std::lock_guard<std::mutex> guard(lock);
340 currentDir.erase(threadID);
341}
342
343int MetaFileSystem::ChDir(const std::string &dir)
344{
345 std::lock_guard<std::mutex> guard(lock);
346 // Retain the old path and fail if the arg is 1023 bytes or longer.
347 if (dir.size() >= 1023)
348 return -1;//SCE_KERNEL_ERROR_NAMETOOLONG;
349
350 _assert_msg_(FILESYS, false, "must implement equiv of __KernelGetCurThread");
351
352 int curThread = 0; //__KernelGetCurThread();
353
354 std::string of;
355 MountPoint *mountPoint;
356 if (MapFilePath(dir, of, &mountPoint))
357 {
358 currentDir[curThread] = mountPoint->prefix + of;
359 return 0;
360 }
361 else
362 {
363 for (size_t i = 0; i < fileSystems.size(); i++)
364 {
365 const std::string &prefix = fileSystems[i].prefix;
366 if (strncasecmp(prefix.c_str(), dir.c_str(), prefix.size()) == 0)
367 {
368 // The PSP is completely happy with invalid current dirs as long as they have a valid device.
369 WARN_LOG(FILESYS, "ChDir failed to map path \"%s\", saving as current directory anyway", dir.c_str());
370 currentDir[curThread] = dir;
371 return 0;
372 }
373 }
374
375 WARN_LOG(FILESYS, "ChDir failed to map device for \"%s\", failing", dir.c_str());
376 return -1;//SCE_KERNEL_ERROR_NODEV;
377 }
378}
379
380bool MetaFileSystem::MkDir(const std::string &dirname)
381{
382 std::lock_guard<std::mutex> guard(lock);
383 std::string of;
384 IFileSystem *system;
385 if (MapFilePath(dirname, of, &system))
386 {
387 return system->MkDir(of);
388 }
389 else
390 {
391 return false;
392 }
393}
394
395bool MetaFileSystem::RmDir(const std::string &dirname)
396{
397 std::lock_guard<std::mutex> guard(lock);
398 std::string of;
399 IFileSystem *system;
400 if (MapFilePath(dirname, of, &system))
401 {
402 return system->RmDir(of);
403 }
404 else
405 {
406 return false;
407 }
408}
409
410int MetaFileSystem::RenameFile(const std::string &from, const std::string &to)
411{
412 std::lock_guard<std::mutex> guard(lock);
413 std::string of;
414 std::string rf;
415 IFileSystem *osystem;
416 IFileSystem *rsystem = NULL;
417 if (MapFilePath(from, of, &osystem))
418 {
419 // If it's a relative path, it seems to always use from's filesystem.
420 if (to.find(":/") != to.npos)
421 {
422 if (!MapFilePath(to, rf, &rsystem))
423 return -1;
424 }
425 else
426 {
427 rf = to;
428 rsystem = osystem;
429 }
430
431 if (osystem != rsystem)
432 return -1;//SCE_KERNEL_ERROR_XDEV;
433
434 return osystem->RenameFile(of, rf);
435 }
436 else
437 {
438 return -1;
439 }
440}
441
442bool MetaFileSystem::RemoveFile(const std::string &filename)
443{
444 std::lock_guard<std::mutex> guard(lock);
445 std::string of;
446 IFileSystem *system;
447 if (MapFilePath(filename, of, &system))
448 {
449 return system->RemoveFile(of);
450 }
451 else
452 {
453 return false;
454 }
455}
456
457void MetaFileSystem::CloseFile(u32 handle)
458{
459 std::lock_guard<std::mutex> guard(lock);
460 IFileSystem *sys = GetHandleOwner(handle);
461 if (sys)
462 sys->CloseFile(handle);
463}
464
465size_t MetaFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size)
466{
467 std::lock_guard<std::mutex> guard(lock);
468 IFileSystem *sys = GetHandleOwner(handle);
469 if (sys)
470 return sys->ReadFile(handle,pointer,size);
471 else
472 return 0;
473}
474
475size_t MetaFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)
476{
477 std::lock_guard<std::mutex> guard(lock);
478 IFileSystem *sys = GetHandleOwner(handle);
479 if (sys)
480 return sys->WriteFile(handle,pointer,size);
481 else
482 return 0;
483}
484
485size_t MetaFileSystem::SeekFile(u32 handle, s32 position, FileMove type)
486{
487 std::lock_guard<std::mutex> guard(lock);
488 IFileSystem *sys = GetHandleOwner(handle);
489 if (sys)
490 return sys->SeekFile(handle,position,type);
491 else
492 return 0;
493}
494
495void MetaFileSystem::DoState(PointerWrap &p)
496{
497 std::lock_guard<std::mutex> guard(lock);
498
499 auto s = p.Section("MetaFileSystem", 1);
500 if (!s)
501 return;
502
503 p.Do(current);
504
505 // Save/load per-thread current directory map
506 p.Do(currentDir);
507
508 u32 n = (u32) fileSystems.size();
509 p.Do(n);
510 if (n != (u32) fileSystems.size())
511 {
512 p.SetError(p.ERROR_FAILURE);
513 ERROR_LOG(FILESYS, "Savestate failure: number of filesystems doesn't match.");
514 return;
515 }
516
517 for (u32 i = 0; i < n; ++i)
518 fileSystems[i].system->DoState(p);
519}
520
diff --git a/src/core/src/file_sys/meta_file_system.h b/src/core/src/file_sys/meta_file_system.h
new file mode 100644
index 000000000..0de23d49c
--- /dev/null
+++ b/src/core/src/file_sys/meta_file_system.h
@@ -0,0 +1,109 @@
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 "std_mutex.h"
21#include "file_sys.h"
22
23class MetaFileSystem : public IHandleAllocator, public IFileSystem
24{
25private:
26 u32 current;
27 struct MountPoint
28 {
29 std::string prefix;
30 IFileSystem *system;
31
32 bool operator == (const MountPoint &other) const
33 {
34 return prefix == other.prefix && system == other.system;
35 }
36 };
37 std::vector<MountPoint> fileSystems;
38
39 typedef std::map<int, std::string> currentDir_t;
40 currentDir_t currentDir;
41
42 std::string startingDirectory;
43 int lastOpenError;
44 std::recursive_mutex lock;
45
46public:
47 MetaFileSystem()
48 {
49 current = 6; // what?
50 }
51
52 void Mount(std::string prefix, IFileSystem *system);
53 void Unmount(std::string prefix, IFileSystem *system);
54
55 void ThreadEnded(int threadID);
56
57 void Shutdown();
58
59 u32 GetNewHandle() {return current++;}
60 void FreeHandle(u32 handle) {}
61
62 virtual void DoState(PointerWrap &p);
63
64 IFileSystem *GetHandleOwner(u32 handle);
65 bool MapFilePath(const std::string &inpath, std::string &outpath, MountPoint **system);
66
67 inline bool MapFilePath(const std::string &_inpath, std::string &outpath, IFileSystem **system)
68 {
69 MountPoint *mountPoint;
70 if (MapFilePath(_inpath, outpath, &mountPoint))
71 {
72 *system = mountPoint->system;
73 return true;
74 }
75
76 return false;
77 }
78
79 // Only possible if a file system is a DirectoryFileSystem or similar.
80 bool GetHostPath(const std::string &inpath, std::string &outpath);
81
82 std::vector<FileInfo> GetDirListing(std::string path);
83 u32 OpenFile(std::string filename, FileAccess access, const char *devicename = NULL);
84 u32 OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename = NULL);
85 void CloseFile(u32 handle);
86 size_t ReadFile(u32 handle, u8 *pointer, s64 size);
87 size_t WriteFile(u32 handle, const u8 *pointer, s64 size);
88 size_t SeekFile(u32 handle, s32 position, FileMove type);
89 FileInfo GetFileInfo(std::string filename);
90 bool OwnsHandle(u32 handle) {return false;}
91 inline size_t GetSeekPos(u32 handle)
92 {
93 return SeekFile(handle, 0, FILEMOVE_CURRENT);
94 }
95
96 virtual int ChDir(const std::string &dir);
97
98 virtual bool MkDir(const std::string &dirname);
99 virtual bool RmDir(const std::string &dirname);
100 virtual int RenameFile(const std::string &from, const std::string &to);
101 virtual bool RemoveFile(const std::string &filename);
102
103 // TODO: void IoCtl(...)
104
105 void SetStartingDirectory(const std::string &dir) {
106 std::lock_guard<std::mutex> guard(lock);
107 startingDirectory = dir;
108 }
109};