// // This file is part of the aMule Project. // // Copyright (c) 2003-2006 aMule Team ( admin@amule.org / http://www.amule.org ) // Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net ) // // Any parts of this program derived from the xMule, lMule or eMule project, // or contributed by third-party developers are copyrighted by their // respective authors. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // #include #include "KnownFileList.h" // Interface declarations #include "CFile.h" // Needed for CFile #include "PartFile.h" // Needed for CPartFile #include // Needed for unicode2char #include "amule.h" #include "MD4Hash.h" // Needed for CMD4Hash #include "Logger.h" #include #include CKnownFileList::CKnownFileList() { accepted = 0; requested = 0; transfered = 0; Init(); } CKnownFileList::~CKnownFileList() { Clear(); } bool CKnownFileList::Init() { CFile file; wxString fullpath = theApp.ConfigDir + wxT("known.met"); if (!wxFileExists(fullpath)) { return false; } if (!file.Open(fullpath)) { return false; } try { if (file.ReadUInt8() != MET_HEADER) { AddLogLineM(true, _("Warning: Knownfile list corrupted, contains invalid header.")); return false; } wxMutexLocker sLock(list_mut); uint32 RecordsNumber = file.ReadUInt32(); for (uint32 i = 0; i < RecordsNumber; i++) { std::auto_ptr record(new CKnownFile()); if (record->LoadFromFile(&file)) { Append(record.release()); } else { AddLogLineM(true, wxT("Failed to load entry in knownfilelist, file may be corrupt")); } } return true; } catch (const CInvalidPacket& e) { AddLogLineM(true, wxT("Invalid entry in knownfilelist, file may be corrupt: ") + e.what()); } catch (const CSafeIOException& e) { AddLogLineM(true, CFormat(_("IO error while reading known.met file: %s")) % e.what()); } return false; } void CKnownFileList::Save() { CFile file(theApp.ConfigDir + wxT("known.met"), CFile::write); if (!file.IsOpened()) { return; } wxMutexLocker sLock(list_mut); try { file.WriteUInt8(MET_HEADER); file.WriteUInt32(m_map.size() + m_duplicates.size()); // Duplicates handling. Duplicates needs to be saved first, // since it is the last entry that gets used. KnownFileList::iterator itDup = m_duplicates.begin(); for ( ; itDup != m_duplicates.end(); ++itDup ) { (*itDup)->WriteToFile(&file); } CKnownFileMap::iterator it = m_map.begin(); for (; it != m_map.end(); ++it) { it->second->WriteToFile(&file); } } catch (const CIOFailureException& e) { AddLogLineM(true, CFormat(_("Error while saving known.met file: %s")) % e.what()); } } void CKnownFileList::Clear() { wxMutexLocker sLock(list_mut); for ( CKnownFileMap::iterator it = m_map.begin(); it != m_map.end(); it++ ) delete it->second; m_map.clear(); KnownFileList::iterator it = m_duplicates.begin(); for ( ; it != m_duplicates.end(); ++it ) { delete *it; } m_duplicates.clear(); } CKnownFile* CKnownFileList::FindKnownFile(wxString filename,uint32 in_date,uint32 in_size){ wxMutexLocker sLock(list_mut); CKnownFile* cur_file; for (CKnownFileMap::iterator pos = m_map.begin(); pos != m_map.end(); pos++ ) { cur_file = pos->second; if ((abs((int)cur_file->GetFileDate() - (int)in_date) < 20) && cur_file->GetFileSize() == in_size && (cur_file->GetFileName() == filename)) { return cur_file; } } return IsOnDuplicates(filename, in_date, in_size); } CKnownFile* CKnownFileList::FindKnownFileByID(const CMD4Hash& hash) { wxMutexLocker sLock(list_mut); if (!hash.IsEmpty()) { if (m_map.find(hash) != m_map.end()) { return m_map[hash]; } else { return NULL; } } return NULL; } bool CKnownFileList::SafeAddKFile(CKnownFile* toadd) { wxMutexLocker sLock(list_mut); return Append(toadd); } bool CKnownFileList::Append(CKnownFile* Record) { if (Record->GetFileSize() > 0) { const CMD4Hash& tkey = Record->GetFileHash(); CKnownFileMap::iterator it = m_map.find(tkey); if ( it == m_map.end() ) { m_map[tkey] = Record; return true; } else { it->second; uint32 in_date = it->second->GetFileDate(); uint32 in_size = it->second->GetFileSize(); wxString filename = it->second->GetFileName(); if (((abs((int)Record->GetFileDate() - (int)in_date) < 20) && Record->GetFileSize() == in_size && (Record->GetFileName() == filename)) || IsOnDuplicates(filename, in_date, in_size)) { // The file is already on the list, ignore it. return false; } else { // The file is a duplicated hash. Add THE OLD ONE to the duplicates list. m_duplicates.push_back(m_map[tkey]); // Is this thread-safe? If John is not sure and I'm not sure either... if (theApp.sharedfiles) { // Removing the old kad keywords created with the old filename theApp.sharedfiles->RemoveKeywords(it->second); } m_map[tkey] = Record; return true; } } } else { AddDebugLogLineM( false, logGeneral, CFormat( wxT("%s is 0-size, not added") ) % Record->GetFileName() ); return false; } } CKnownFile* CKnownFileList::IsOnDuplicates(wxString filename,uint32 in_date,uint32 in_size) const { KnownFileList::const_iterator it = m_duplicates.begin(); for ( ; it != m_duplicates.end(); ++it ) { CKnownFile* cur_file = *it; if ((abs((int)cur_file->GetFileDate() - (int)in_date) < 20) && cur_file->GetFileSize() == in_size && (cur_file->GetFileName() == filename)) { return cur_file; } } return NULL; } bool CKnownFileList::IsKnownFile(const CKnownFile* file) { if (file) { return FindKnownFileByID(file->GetFileHash()) != NULL; } return false; }