src/Emu/Utility/System/VirtualSystem.cpp

説明を見る。
00001 // 
00002 // Copyright (c) 2005-2008 Kenichi Watanabe.
00003 // Copyright (c) 2005-2008 Yasuhiro Watari.
00004 // Copyright (c) 2005-2008 Hironori Ichibayashi.
00005 // Copyright (c) 2008-2009 Kazuo Horio.
00006 // Copyright (c) 2009-2013 Naruki Kurata.
00007 // Copyright (c) 2005-2013 Ryota Shioya.
00008 // Copyright (c) 2005-2013 Masahiro Goshima.
00009 // 
00010 // This software is provided 'as-is', without any express or implied
00011 // warranty. In no event will the authors be held liable for any damages
00012 // arising from the use of this software.
00013 // 
00014 // Permission is granted to anyone to use this software for any purpose,
00015 // including commercial applications, and to alter it and redistribute it
00016 // freely, subject to the following restrictions:
00017 // 
00018 // 1. The origin of this software must not be misrepresented; you must not
00019 // claim that you wrote the original software. If you use this software
00020 // in a product, an acknowledgment in the product documentation would be
00021 // appreciated but is not required.
00022 // 
00023 // 2. Altered source versions must be plainly marked as such, and must not be
00024 // misrepresented as being the original software.
00025 // 
00026 // 3. This notice may not be removed or altered from any source
00027 // distribution.
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 // const int FDConv::InvalidFD;
00042 // NXstatic const AhXC`KvC
00043 // `uCVCoOd`iNG[j
00044 // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=99610
00045 
00046 
00047 //
00048 // FDConv
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     // targetFD
00100     if (m_FDTargetToHostTable[targetFD] == InvalidFD)
00101         return false;
00102 
00103     m_FDTargetToHostTable[targetFD] = InvalidFD;
00104 
00105     return true;
00106 }
00107 
00108 // targetfdT
00109 int FDConv::GetFirstFreeFD()
00110 {
00111     // \hostfdT
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         // \g
00118         int result = (int)m_FDTargetToHostTable.size();
00119         ExtendFDMap();
00120         return result;
00121     }
00122 }
00123 
00124 // m_FDTargetToHostTable TCY
00125 void FDConv::ExtendFDMap()
00126 {
00127     ExtendFDMap(m_FDTargetToHostTable.size()*2);
00128 }
00129 
00130 // m_FDTargetToHostTable TCYwTCY ()
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 // DelayUnlinker
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 // VirtualSystem
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     // FD\
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     // FD\
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         // closeゥN[YXgO
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     /* unlink 
00407     Unix AvZX open 
00408     t@C unlink AvZX
00409     close _t@CB
00410     AWindows  open t@C unlink 
00411     G[B
00412      Windows  Unix  DelayUnlinker NXp
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 

Onikiri2に対してTue Jun 18 14:34:20 2013に生成されました。  doxygen 1.4.7