#include "vfs_directory_tree.h" #include "../File/vfs_dir_file.h" #include "../Interface/vfs_location_aware_file_interface.h" #include "../os_functions.h" #include #include #include #define ERROR_FILE(msg) BuildString().add((msg)).add(L" : ").add(pFile->getPath()).get() namespace vfs { template class TSubDir : public vfs::TDirectory::tWriteType> { typedef vfs::TDirectory::tWriteType> tBaseClass; typedef typename tBaseClass::tFileType tFileType; typedef std::map tFileCatalogue; public: typedef vfs::IBaseLocation::Iterator Iterator; ///////////////////////////////////////////////////////////////////// class IterImpl : public vfs::IBaseLocation::Iterator::IImplementation { friend class TSubDir; typedef vfs::IBaseLocation::Iterator::IImplementation tBaseClass; IterImpl(TSubDir* dir): _dir(dir) { THROWIFFALSE(_dir, L""); _iter = _dir->m_mapFiles.begin(); } public: IterImpl() : tBaseClass(), _dir(NULL) {}; virtual ~IterImpl() {}; virtual tFileType* value() { if(_iter != _dir->m_mapFiles.end()) { return _iter->second; } return NULL; } virtual void next() { if(_iter != _dir->m_mapFiles.end()) { _iter++; } } protected: tBaseClass* clone() { IterImpl* iter = new IterImpl(); iter->_dir = _dir; iter->_iter = _iter; return iter; } private: TSubDir* _dir; typename tFileCatalogue::iterator _iter; }; ///////////////////////////////////////////////////////////////////// public: TSubDir(vfs::Path const& sMountPoint, vfs::Path const& sRealPath) : tBaseClass(sMountPoint,sRealPath) {}; virtual ~TSubDir(); virtual bool fileExists(vfs::Path const& rFileName); virtual vfs::IBaseFile* getFile(vfs::Path const& rFileName); virtual tFileType* getFileTyped(vfs::Path const& rFileName); virtual tFileType* addFile(vfs::Path const& sFilename, bool bDeleteOldFile=false); virtual bool addFile(tFileType* pFile, bool bDeleteOldFile=false); virtual bool createSubDirectory(vfs::Path const& sSubDirPath); virtual bool deleteDirectory(vfs::Path const& sDirPath); virtual bool deleteFileFromDirectory(vfs::Path const& sFileName); virtual void getSubDirList(std::list& rlSubDirs); virtual Iterator begin(); private: tFileCatalogue m_mapFiles; }; template<> vfs::TSubDir::tFileType* vfs::TSubDir::addFile(vfs::Path const& sFilename, bool bDeleteOldFile); template<> vfs::TSubDir::tFileType* vfs::TSubDir::addFile(vfs::Path const& sFilename, bool bDeleteOldFile); template<> bool vfs::TSubDir::deleteDirectory(vfs::Path const& sDirPath); template<> bool vfs::TSubDir::deleteDirectory(vfs::Path const& sDirPath); template<> bool vfs::TSubDir::deleteFileFromDirectory(vfs::Path const& rFileName); template<> bool vfs::TSubDir::deleteFileFromDirectory(vfs::Path const& rFileName); } /********************************************************/ template vfs::TSubDir::~TSubDir() { typename tFileCatalogue::iterator it = m_mapFiles.begin(); for(; it != m_mapFiles.end(); ++it) { if(it->second) { it->second->close(); delete it->second; } } m_mapFiles.clear(); } template bool vfs::TSubDir::fileExists(vfs::Path const& sFileName) { typename tFileCatalogue::iterator it = m_mapFiles.find(sFileName); bool success = (it != m_mapFiles.end()) && (it->second != NULL); return success; } template vfs::IBaseFile* vfs::TSubDir::getFile(vfs::Path const& sFileName) { return getFileTyped(sFileName); } template typename vfs::TSubDir::tFileType* vfs::TSubDir::getFileTyped(vfs::Path const& sFileName) { typename tFileCatalogue::iterator it = m_mapFiles.find(sFileName); if(it != m_mapFiles.end()) { return it->second; } return NULL; } template<> vfs::TSubDir::tFileType* vfs::TSubDir::addFile(vfs::Path const& sFilename, bool bDeleteOldFile) { tFileType* pFile = m_mapFiles[sFilename]; if(pFile) { if(!bDeleteOldFile) { // not allowed to replace old file return NULL; } delete pFile; } pFile = new vfs::CReadOnlyDirFile(sFilename,this); m_mapFiles[sFilename] = pFile; return pFile; } template<> vfs::TSubDir::tFileType* vfs::TSubDir::addFile(vfs::Path const& sFilename, bool bDeleteOldFile) { tFileType* pFile = m_mapFiles[sFilename]; if(pFile) { if(!bDeleteOldFile) { // not allowed to replace old file return NULL; } delete pFile; } pFile = new vfs::CDirFile(sFilename,this); m_mapFiles[sFilename] = pFile; return pFile; } template bool vfs::TSubDir::addFile(tFileType* pFile, bool bDeleteOldFile) { if(!pFile) { return false; } tFileType* pOldFile = m_mapFiles[pFile->getName()]; if( pOldFile && (pOldFile != pFile) ) { if(bDeleteOldFile) { pOldFile->close(); delete pOldFile; } } m_mapFiles[pFile->getName()] = pFile; return true; } template<> bool vfs::TSubDir::deleteDirectory(vfs::Path const& sDirPath) { if( !(this->m_mountPoint == sDirPath) ) { return false; } tFileCatalogue::iterator it = m_mapFiles.begin(); for(; it != m_mapFiles.end(); ++it) { tFileType* pFile = it->second; if(pFile) { pFile->close(); if(!pFile->deleteFile()) { std::wstringstream wss; wss << L"Could not delete file \"" << pFile->getPath()() << L"\""; THROWEXCEPTION( ERROR_FILE(L"Could not delete file") ); } delete pFile; } } m_mapFiles.clear(); return true; } template<> bool vfs::TSubDir::deleteDirectory(vfs::Path const& sDirPath) { return false; } template<> bool vfs::TSubDir::deleteFileFromDirectory(vfs::Path const& rFileName) { tFileCatalogue::iterator it = m_mapFiles.find(rFileName); if( it != m_mapFiles.end() ) { tFileType* pFile = it->second; if(pFile) { pFile->close(); THROWIFFALSE(pFile->deleteFile(), ERROR_FILE(L"Could not delete file")); delete pFile; } m_mapFiles.erase(it); return true; } return false; } template<> bool vfs::TSubDir::deleteFileFromDirectory(vfs::Path const& rFileName) { return false; } template bool vfs::TSubDir::createSubDirectory(vfs::Path const& sSubDirPath) { return false; } template void vfs::TSubDir::getSubDirList(std::list& rlSubDirs) { } template typename vfs::TSubDir::Iterator vfs::TSubDir::begin() { return Iterator(new IterImpl(this)); } /********************************************************************************************/ /********************************************************************************************/ /********************************************************************************************/ template class vfs::TDirectoryTree::IterImpl : public vfs::IBaseLocation::Iterator::IImplementation { typedef vfs::IBaseLocation::Iterator::IImplementation tBaseClass; typedef vfs::TDirectoryTree tDirTree; public: IterImpl(tDirTree& tree); virtual ~IterImpl(); virtual typename tDirTree::tFileType* value(); virtual void next(); protected: virtual tBaseClass* clone() { IterImpl* iter = new IterImpl(_tree); iter->_subdir_iter = _subdir_iter; iter->_file_iter = _file_iter; return iter; } private: void operator=(typename vfs::TDirectoryTree::IterImpl const& tree); tDirTree& _tree; typename tDirTree::tDirCatalogue::iterator _subdir_iter; typename tDirTree::tLocationType::Iterator _file_iter; }; template vfs::TDirectoryTree::IterImpl::IterImpl(vfs::TDirectoryTree& tree) : tBaseClass(), _tree(tree) { _subdir_iter = _tree.m_catDirs.begin(); if(_subdir_iter != _tree.m_catDirs.end()) { TSubDir *sdir = dynamic_cast*>(_subdir_iter->second); typename TSubDir::Iterator it = sdir->begin(); _file_iter = it; if(_file_iter.end()) { next(); } } } template vfs::TDirectoryTree::IterImpl::~IterImpl() { } template typename vfs::TDirectoryTree::tFileType* vfs::TDirectoryTree::IterImpl::value() { if(!_file_iter.end()) { return static_cast::tFileType*>(_file_iter.value()); } return NULL; } template void vfs::TDirectoryTree::IterImpl::next() { if(!_file_iter.end()) { _file_iter.next(); } // need to loop for the case when one or many sub directories are empty while(_file_iter.end()) { if(_subdir_iter == _tree.m_catDirs.end()) { break; } else { _subdir_iter++; if(_subdir_iter != _tree.m_catDirs.end()) { _file_iter = _subdir_iter->second->begin(); } } } return; } /*****************************************************************************/ /*****************************************************************************/ template vfs::TDirectoryTree::TDirectoryTree(vfs::Path const& sMountPoint, vfs::Path const& sRealPath) : tBaseClass(sMountPoint,sRealPath) {}; template vfs::TDirectoryTree::~TDirectoryTree() { typename tDirCatalogue::iterator it = m_catDirs.begin(); for(;it != m_catDirs.end(); ++it) { delete it->second; it->second = NULL; } m_catDirs.clear(); } template bool vfs::TDirectoryTree::init() { // contains local path typedef vfs::TSubDir tSubDir; typedef std::pair tDirs; std::queue qSubDirs; qSubDirs.push(tDirs(vfs::Path(vfs::Const::EMPTY()),new tSubDir(this->m_mountPoint, this->m_realPath))); m_catDirs[this->m_mountPoint] = qSubDirs.front().second; utf8string sFilename; tSubDir *pCurrentDir; vfs::Path oCurDir; while(!qSubDirs.empty()) { pCurrentDir = qSubDirs.front().second; oCurDir = this->m_realPath; if( !qSubDirs.front().first.empty()) { oCurDir += qSubDirs.front().first; } try { os::CIterateDirectory::EFileAttribute eFA; os::CIterateDirectory iterFS(oCurDir, vfs::Const::STAR()); while ( iterFS.nextFile(sFilename, eFA) ) { if (StrCmp::Equal(vfs::Const::DOT(),sFilename) || StrCmp::Equal(vfs::Const::DOTDOT(),sFilename) || StrCmp::Equal(vfs::Const::DOTSVN(),sFilename) ) { continue; } if (eFA == os::CIterateDirectory::FA_DIRECTORY) { vfs::Path sLocal = qSubDirs.front().first + sFilename; vfs::Path temp = this->m_mountPoint+sLocal; tSubDir *pNewDir = new tSubDir(sLocal, this->m_realPath+sLocal); qSubDirs.push(tDirs(sLocal,pNewDir)); m_catDirs[temp] = pNewDir; } else { pCurrentDir->addFile(vfs::Path(sFilename)); } } } catch(CBasicException &ex) { // probably directory doesn't exist. abort or continue??? // -> abort AND continue logException(ex); return false; } qSubDirs.pop(); } return true; } template typename vfs::TDirectoryTree::tFileType* vfs::TDirectoryTree::addFile(vfs::Path const& sFilename, bool bDeleteOldFile) { vfs::Path sDir,sFile; sFilename.splitLast(sDir,sFile); typename tDirCatalogue::iterator it = m_catDirs.find(sDir); if(it == m_catDirs.end()) { vfs::Path sTemp,sCreateDir,sLeft,sRight = sDir; while(!sRight.empty()) { sRight.splitFirst(sLeft,sTemp); sRight = sTemp; sCreateDir += sLeft; this->createSubDirectory(sCreateDir); } it = m_catDirs.find(sDir); if(it == m_catDirs.end()) { return NULL; } } if(it->second) { return it->second->addFile(sFile,bDeleteOldFile); } return NULL; } template bool vfs::TDirectoryTree::addFile(tFileType* pFile, bool bDeleteOldFile) { // no files from outside // these files are not connected with the correct directory object return false; } template bool vfs::TDirectoryTree::deleteDirectory(vfs::Path const& sDirPath) { typename tDirCatalogue::iterator it = m_catDirs.find(sDirPath); if(it == m_catDirs.end()) { // no such directory return false; } if(it->second) { return it->second->deleteDirectory(sDirPath); } return false; } template bool vfs::TDirectoryTree::deleteFileFromDirectory(vfs::Path const& sFileName) { vfs::Path sDir,sFile; sFileName.splitLast(sDir,sFile); typename tDirCatalogue::iterator it = m_catDirs.find(sDir); if(it == m_catDirs.end()) { // no such directory return false; } if(it->second) { return it->second->deleteFileFromDirectory(sFile); } return false; } /** * IVFSLocation interface */ template bool vfs::TDirectoryTree::fileExists(vfs::Path const& sFileName) { vfs::Path sDir, sFile; sFileName.splitLast(sDir, sFile); typename tDirCatalogue::iterator it = m_catDirs.find(sDir); if(it == m_catDirs.end()) { // no such directory return false; } if(it->second) { return it->second->fileExists(sFile); } return false; } template vfs::IBaseFile* vfs::TDirectoryTree::getFile(vfs::Path const& sFileName) { return getFileTyped(sFileName); } template typename vfs::TDirectoryTree::tFileType* vfs::TDirectoryTree::getFileTyped(vfs::Path const& sFileName) { vfs::Path sDir, sFile; sFileName.splitLast(sDir, sFile); typename tDirCatalogue::iterator it = m_catDirs.find(sDir); if(it == m_catDirs.end()) { // no such directory return NULL; } if(it->second) { return it->second->getFileTyped(sFile); } return NULL; } template bool vfs::TDirectoryTree::createSubDirectory(vfs::Path const& sSubDirPath) { if(os::createRealDirectory( this->m_realPath + sSubDirPath )) { if( m_catDirs[sSubDirPath] == NULL) { m_catDirs[sSubDirPath] = new vfs::TSubDir(sSubDirPath, this->m_realPath + sSubDirPath); } return true; } return false; } template void vfs::TDirectoryTree::getSubDirList(std::list& rlSubDirs) { typename tDirCatalogue::iterator it = m_catDirs.begin(); for(;it != m_catDirs.end(); ++it) { rlSubDirs.push_back(it->first); } } template typename vfs::TDirectoryTree::Iterator vfs::TDirectoryTree::begin() { return Iterator(new IterImpl(*this)); } /*****************************************************************************/ /*****************************************************************************/ template class vfs::TDirectoryTree; // explicit template class instantiation template class vfs::TDirectoryTree; // explicit template class instantiation