00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <pch.h>
00033 #include "Emu/Utility/System/VirtualSystem.h"
00034
00035 using namespace std;
00036 using namespace boost;
00037 using namespace Onikiri;
00038 using namespace Onikiri::EmulatorUtility;
00039 using namespace Onikiri::POSIX;
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 FDConv::FDConv()
00051 {
00052 ExtendFDMap(8);
00053 }
00054
00055 FDConv::~FDConv()
00056 {
00057 }
00058
00059 int FDConv::TargetToHost(int targetFD) const
00060 {
00061 if (targetFD < 0)
00062 return InvalidFD;
00063
00064 if ((size_t)targetFD < m_FDTargetToHostTable.size())
00065 return m_FDTargetToHostTable[targetFD];
00066 else
00067 return InvalidFD;
00068 }
00069
00070 int FDConv::HostToTarget(int hostFD) const
00071 {
00072 if (hostFD < 0)
00073 return InvalidFD;
00074
00075 vector<int>::const_iterator e = find(m_FDTargetToHostTable.begin(), m_FDTargetToHostTable.end(), hostFD);
00076 if (e != m_FDTargetToHostTable.end())
00077 return (int)(e - m_FDTargetToHostTable.begin());
00078 else
00079 return InvalidFD;
00080 }
00081 bool FDConv::AddMap(int targetFD, int hostFD)
00082 {
00083 if (targetFD < 0 || hostFD < 0)
00084 return false;
00085
00086 if ((size_t)targetFD >= m_FDTargetToHostTable.size())
00087 ExtendFDMap();
00088
00089 m_FDTargetToHostTable[targetFD] = hostFD;
00090
00091 return true;
00092 }
00093
00094 bool FDConv::RemoveMap(int targetFD)
00095 {
00096 if (targetFD < 0)
00097 return false;
00098
00099
00100 if (m_FDTargetToHostTable[targetFD] == InvalidFD)
00101 return false;
00102
00103 m_FDTargetToHostTable[targetFD] = InvalidFD;
00104
00105 return true;
00106 }
00107
00108
00109 int FDConv::GetFirstFreeFD()
00110 {
00111
00112 vector<int>::iterator e = find(m_FDTargetToHostTable.begin(), m_FDTargetToHostTable.end(), (int)InvalidFD);
00113
00114 if (e != m_FDTargetToHostTable.end())
00115 return (int)(e - m_FDTargetToHostTable.begin());
00116 else {
00117
00118 int result = (int)m_FDTargetToHostTable.size();
00119 ExtendFDMap();
00120 return result;
00121 }
00122 }
00123
00124
00125 void FDConv::ExtendFDMap()
00126 {
00127 ExtendFDMap(m_FDTargetToHostTable.size()*2);
00128 }
00129
00130
00131 void FDConv::ExtendFDMap(size_t size)
00132 {
00133 if (size > m_FDTargetToHostTable.size())
00134 m_FDTargetToHostTable.resize(size, (int)InvalidFD);
00135 }
00136
00137
00138
00139
00140 DelayUnlinker::DelayUnlinker()
00141 {
00142 }
00143
00144 DelayUnlinker::~DelayUnlinker()
00145 {
00146 }
00147
00148 bool DelayUnlinker::AddMap(int targetFD, string path)
00149 {
00150 if(targetFD < 0){
00151 return false;
00152 }
00153 m_targetFDToPathTable[targetFD] = path;
00154
00155 return true;
00156 }
00157
00158 bool DelayUnlinker::RemoveMap(int targetFD)
00159 {
00160 if(targetFD < 0){
00161 return false;
00162 }
00163 m_targetFDToPathTable[targetFD] = "";
00164
00165 return true;
00166 }
00167
00168 string DelayUnlinker::GetMapPath(int targetFD)
00169 {
00170 ASSERT( m_targetFDToPathTable[targetFD] != "", "Invalid map path." )
00171 return m_targetFDToPathTable[targetFD];
00172 }
00173
00174 bool DelayUnlinker::AddUnlinkPath(string path)
00175 {
00176 list<string>::iterator i;
00177 for(i = m_delayUnlinkPathList.begin(); i != m_delayUnlinkPathList.end(); ++i){
00178 if(*i == path){
00179 return false;
00180 }
00181 }
00182 m_delayUnlinkPathList.push_back(path);
00183
00184 return true;
00185 }
00186
00187 bool DelayUnlinker::IfUnlinkable(int targetFD)
00188 {
00189 map<int, string>::const_iterator i;
00190 string targetPath = m_targetFDToPathTable[targetFD];
00191 for(i = m_targetFDToPathTable.begin(); i != m_targetFDToPathTable.end(); ++i){
00192 if(i->first == targetFD){
00193 continue;
00194 }
00195 if(i->second == targetPath){
00196 return false;
00197 }
00198 }
00199
00200 bool pathInList = false;
00201 list<string>::const_iterator j;
00202 for(j = m_delayUnlinkPathList.begin(); j != m_delayUnlinkPathList.end(); ++j){
00203 if(*j == targetPath){
00204 pathInList = true;
00205 }
00206 }
00207 return pathInList;
00208 }
00209
00210 bool DelayUnlinker::RemoveUnlinkPath(string path)
00211 {
00212 list<string>::iterator i;
00213 for(i = m_delayUnlinkPathList.begin(); i != m_delayUnlinkPathList.end(); ++i){
00214 if(*i == path){
00215 i = m_delayUnlinkPathList.erase(i);
00216 return true;
00217 }
00218 }
00219 return false;
00220 }
00221
00222
00223
00224
00225
00226
00227
00228 VirtualSystem::VirtualSystem()
00229 {
00230 LoadParam();
00231 m_executedInsnTick = 0;
00232 m_timeEmulationMode = EmulationModeStrToInt( m_timeEmulationModeStr );
00233 }
00234
00235 VirtualSystem::~VirtualSystem()
00236 {
00237 ReleaseParam();
00238 for_each(m_autoCloseFD.begin(), m_autoCloseFD.end(), posix_close);
00239 }
00240
00241 void VirtualSystem::SetInitialWorkingDir(const boost::filesystem::path& dir)
00242 {
00243 m_cwd = dir;
00244 }
00245
00246 bool VirtualSystem::AddFDMap(int targetFD, int hostFD, bool autoclose)
00247 {
00248 if (!m_fdConv.AddMap(targetFD, hostFD))
00249 return false;
00250
00251 if (autoclose)
00252 AddAutoCloseFD(hostFD);
00253
00254 return true;
00255 }
00256
00257 int VirtualSystem::GetErrno()
00258 {
00259 return posix_geterrno();
00260 }
00261
00262 void VirtualSystem::AddAutoCloseFD(int fd)
00263 {
00264 if (find(m_autoCloseFD.begin(), m_autoCloseFD.end(), fd) == m_autoCloseFD.end())
00265 m_autoCloseFD.push_back(fd);
00266 }
00267
00268 void VirtualSystem::RemoveAutoCloseFD(int fd)
00269 {
00270 vector<int>::iterator e = find(m_autoCloseFD.begin(), m_autoCloseFD.end(), fd);
00271 if (e != m_autoCloseFD.end())
00272 m_autoCloseFD.erase(e);
00273 }
00274
00275 char* VirtualSystem::GetCWD(char* buf, int maxlen)
00276 {
00277 strncpy(buf, m_cwd.string().c_str(), maxlen);
00278 return buf;
00279 }
00280
00281 int VirtualSystem::ChDir(const char* path)
00282 {
00283 ASSERT(0);
00284 return -1;
00285 }
00286
00287 int VirtualSystem::GetPID()
00288 {
00289 return posix_getpid();
00290 }
00291
00292 int VirtualSystem::GetUID()
00293 {
00294 return posix_getuid();
00295 }
00296
00297 int VirtualSystem::GetEUID()
00298 {
00299 return posix_geteuid();
00300 }
00301
00302 int VirtualSystem::GetGID()
00303 {
00304 return posix_getgid();
00305 }
00306
00307 int VirtualSystem::GetEGID()
00308 {
00309 return posix_getegid();
00310 }
00311
00312 int VirtualSystem::Open(const char* filename, int oflag)
00313 {
00314 int hostFD = posix_open(GetHostPath(filename).string().c_str(), oflag, POSIX_S_IWRITE | POSIX_S_IREAD);
00315
00316
00317 if (hostFD != -1) {
00318 int targetFD = m_fdConv.GetFirstFreeFD();
00319 AddFDMap(targetFD, hostFD, true);
00320 m_delayUnlinker.AddMap(targetFD, GetHostPath(filename).string());
00321 return targetFD;
00322 }
00323 else {
00324 return -1;
00325 }
00326 }
00327
00328 int VirtualSystem::Dup(int fd)
00329 {
00330 int hostFD = FDTargetToHost(fd);
00331 int dupHostFD = posix_dup(hostFD);
00332
00333 if (dupHostFD != -1) {
00334 int targetFD = m_fdConv.GetFirstFreeFD();
00335 AddFDMap(targetFD, dupHostFD, true);
00336 m_delayUnlinker.AddMap(targetFD, m_delayUnlinker.GetMapPath(fd));
00337 return targetFD;
00338 }
00339 else {
00340 return -1;
00341 }
00342 }
00343
00344
00345 int VirtualSystem::Read(int fd, void* buffer, unsigned int count)
00346 {
00347 int hostFD = m_fdConv.TargetToHost(fd);
00348 return posix_read(hostFD, buffer, count);
00349 }
00350
00351 int VirtualSystem::Write(int fd, void* buffer, unsigned int count)
00352 {
00353 int hostFD = m_fdConv.TargetToHost(fd);
00354 return posix_write(hostFD, buffer, count);
00355 }
00356
00357 int VirtualSystem::Close(int fd)
00358 {
00359 int hostFD = m_fdConv.TargetToHost(fd);
00360 int result = posix_close(hostFD);
00361 if (result != -1) {
00362
00363 RemoveAutoCloseFD(hostFD);
00364
00365 m_fdConv.RemoveMap(fd);
00366 #ifdef HOST_IS_WINDOWS
00367 if( m_delayUnlinker.IfUnlinkable(fd) ){
00368 m_delayUnlinker.RemoveUnlinkPath(m_delayUnlinker.GetMapPath(fd));
00369 posix_unlink(m_delayUnlinker.GetMapPath(fd).c_str());
00370 }
00371 #endif
00372 m_delayUnlinker.RemoveMap(fd);
00373 }
00374
00375 return result;
00376 }
00377
00378 int VirtualSystem::FStat(int fd, HostStat* buffer)
00379 {
00380 int hostFD = FDTargetToHost(fd);
00381 return posix_fstat(hostFD, buffer);
00382 }
00383
00384 int VirtualSystem::Stat(const char* path, posix_struct_stat* s)
00385 {
00386 return posix_stat(GetHostPath(path).string().c_str(), s);
00387 }
00388 int VirtualSystem::LStat(const char* path, posix_struct_stat* s)
00389 {
00390 return posix_lstat(GetHostPath(path).string().c_str(), s);
00391 }
00392
00393 s64 VirtualSystem::LSeek(int fd, s64 offset, int whence)
00394 {
00395 int hostFD = FDTargetToHost(fd);
00396 return posix_lseek(hostFD, offset, whence);
00397 }
00398
00399 int VirtualSystem::Access(const char* path, int mode)
00400 {
00401 return posix_access(GetHostPath(path).string().c_str(), mode);
00402 }
00403
00404 int VirtualSystem::Unlink(const char* path)
00405 {
00406
00407
00408
00409
00410
00411
00412
00413
00414 int unlinkerr = posix_unlink(GetHostPath(path).string().c_str());
00415 #ifdef HOST_IS_WINDOWS
00416 if( posix_geterrno() == 0xd ){
00417 m_delayUnlinker.AddUnlinkPath(GetHostPath(path).string());
00418 return 0;
00419 }
00420 #endif
00421 return unlinkerr;
00422 }
00423
00424 int VirtualSystem::Rename(const char* oldpath, const char* newpath)
00425 {
00426 return posix_rename((m_cwd/oldpath).string().c_str(), (m_cwd/newpath).string().c_str());
00427 }
00428
00429 int VirtualSystem::Truncate(const char* path, s64 length)
00430 {
00431 return posix_truncate(GetHostPath(path).string().c_str(), length);
00432 }
00433
00434 int VirtualSystem::FTruncate(int fd, s64 length)
00435 {
00436 int hostFD = FDTargetToHost(fd);
00437 return posix_ftruncate(hostFD, length);
00438 }
00439
00440 int VirtualSystem::MkDir(const char* path, int mode)
00441 {
00442 namespace fs = filesystem;
00443 if (fs::create_directory( GetHostPath(path) ))
00444 return 0;
00445 else
00446 return -1;
00447 }
00448
00449 boost::filesystem::path VirtualSystem::GetHostPath(const char* targetPath)
00450 {
00451 namespace fs = filesystem;
00452 return fs::absolute(fs::path(targetPath), m_cwd);
00453 }
00454
00455
00456
00457
00458
00459 int VirtualSystem::EmulationModeStrToInt( const std::string& str )
00460 {
00461 if(str == "Host"){
00462 return TIME_HOST;
00463 }
00464 else if(str == "Fixed"){
00465 return TIME_FIXED;
00466 }
00467 else if(str == "InstructionBased"){
00468 return TIME_INSTRUCTION;
00469 }
00470 else{
00471 THROW_RUNTIME_ERROR(
00472 "'Emulator/System/Time/@EmulationMode' must be one of the following strings: "
00473 "'Host', 'Fixed', 'InstructionBased'"
00474 );
00475 return -1;
00476 }
00477 }
00478
00479 static const int INSN_PER_SEC = 2000000000;
00480
00481 s64 VirtualSystem::GetTime()
00482 {
00483 switch(m_timeEmulationMode){
00484 default:
00485 case TIME_HOST:
00486 return time(NULL);
00487 case TIME_FIXED:
00488 return m_unixTime;
00489 case TIME_INSTRUCTION:
00490 return m_unixTime + m_executedInsnTick/INSN_PER_SEC;
00491 }
00492 }
00493
00494 s64 VirtualSystem::GetClock()
00495 {
00496 switch(m_timeEmulationMode){
00497 default:
00498 case TIME_HOST:
00499 return clock();
00500 case TIME_FIXED:
00501 return 0;
00502 case TIME_INSTRUCTION:
00503 return m_executedInsnTick/(INSN_PER_SEC/1000);
00504 }
00505 }
00506