Updated Hungarian translation by GonoszTopi
[amule.git] / src / KnownFileList.cpp
blob880467360385b5b36207fcedc9a01e73db6d626f
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "KnownFileList.h" // Interface declarations
29 #include <common/DataFileVersion.h>
31 #include <memory> // Do_not_auto_remove (lionel's Mac, 10.3)
32 #include "PartFile.h" // Needed for CPartFile
33 #include "amule.h"
34 #include "Logger.h"
35 #include "MemFile.h"
36 #include "ScopedPtr.h"
37 #include "SearchList.h" // Needed for UpdateSearchFileByHash
38 #include <common/Format.h>
41 // This function is inlined for performance
42 inline bool CKnownFileList::KnownFileMatches(
43 CKnownFile *knownFile,
44 const CPath& filename,
45 uint32 in_date,
46 uint64 in_size) const
48 return
49 (knownFile->GetLastChangeDatetime() == (time_t)in_date) &&
50 (knownFile->GetFileSize() == in_size) &&
51 (knownFile->GetFileName() == filename);
55 CKnownFileList::CKnownFileList()
57 accepted = 0;
58 requested = 0;
59 transferred = 0;
60 m_filename = wxT("known.met");
61 m_knownSizeMap = NULL;
62 m_duplicateSizeMap = NULL;
63 Init();
67 CKnownFileList::~CKnownFileList()
69 Clear();
73 bool CKnownFileList::Init()
75 CFile file;
77 CPath fullpath = CPath(theApp->ConfigDir + m_filename);
78 if (!fullpath.FileExists()) {
79 // This is perfectly normal. The file was probably either
80 // deleted, or this is the first time running aMule.
81 return false;
84 if (!file.Open(fullpath)) {
85 AddLogLineC(CFormat(_("WARNING: %s cannot be opened.")) % m_filename);
86 return false;
89 try {
90 uint8 version = file.ReadUInt8();
91 if ((version != MET_HEADER) && (version != MET_HEADER_WITH_LARGEFILES)) {
92 AddLogLineC(_("WARNING: Known file list corrupted, contains invalid header."));
93 return false;
96 wxMutexLocker sLock(list_mut);
97 uint32 RecordsNumber = file.ReadUInt32();
98 AddDebugLogLineN(logKnownFiles, CFormat(wxT("Reading %i known files from file format 0x%2.2x."))
99 % RecordsNumber % version);
100 for (uint32 i = 0; i < RecordsNumber; i++) {
101 CScopedPtr<CKnownFile> record;
102 if (record->LoadFromFile(&file)) {
103 AddDebugLogLineN(logKnownFiles,
104 CFormat(wxT("Known file read: %s")) % record->GetFileName());
105 Append(record.release());
106 } else {
107 AddLogLineC(_("Failed to load entry in known file list, file may be corrupt"));
110 AddDebugLogLineN(logKnownFiles, wxT("Finished reading known files"));
112 return true;
113 } catch (const CInvalidPacket& e) {
114 AddLogLineC(_("Invalid entry in known file list, file may be corrupt: ") + e.what());
115 } catch (const CSafeIOException& e) {
116 AddLogLineC(CFormat(_("IO error while reading %s file: %s")) % m_filename % e.what());
119 return false;
123 void CKnownFileList::Save()
125 CFile file(theApp->ConfigDir + m_filename, CFile::write_safe);
126 if (!file.IsOpened()) {
127 return;
130 wxMutexLocker sLock(list_mut);
131 AddDebugLogLineN(logKnownFiles, CFormat(wxT("start saving %s")) % m_filename);
133 try {
134 // Kry - This is the version, but we don't know it till
135 // we know if any largefile is saved. This allows the list
136 // to be compatible with previous versions.
137 bool bContainsAnyLargeFiles = false;
138 file.WriteUInt8(0);
140 file.WriteUInt32(m_knownFileMap.size() + m_duplicateFileList.size());
142 // Duplicates handling. Duplicates needs to be saved first,
143 // since it is the last entry that gets used.
144 KnownFileList::iterator itDup = m_duplicateFileList.begin();
145 for ( ; itDup != m_duplicateFileList.end(); ++itDup ) {
146 (*itDup)->WriteToFile(&file);
147 if ((*itDup)->IsLargeFile()) {
148 bContainsAnyLargeFiles = true;
152 CKnownFileMap::iterator it = m_knownFileMap.begin();
153 for (; it != m_knownFileMap.end(); ++it) {
154 it->second->WriteToFile(&file);
155 if (it->second->IsLargeFile()) {
156 bContainsAnyLargeFiles = true;
160 file.Seek(0);
161 file.WriteUInt8(bContainsAnyLargeFiles ? MET_HEADER_WITH_LARGEFILES : MET_HEADER);
162 file.Close();
163 } catch (const CIOFailureException& e) {
164 AddLogLineC(CFormat(_("Error while saving %s file: %s")) % m_filename % e.what());
166 AddDebugLogLineN(logKnownFiles, CFormat(wxT("finished saving %s")) % m_filename);
170 void CKnownFileList::Clear()
172 wxMutexLocker sLock(list_mut);
174 DeleteContents(m_knownFileMap);
175 DeleteContents(m_duplicateFileList);
176 ReleaseIndex();
180 CKnownFile* CKnownFileList::FindKnownFile(
181 const CPath& filename,
182 time_t in_date,
183 uint64 in_size)
185 wxMutexLocker sLock(list_mut);
187 if (m_knownSizeMap) {
188 std::pair<KnownFileSizeMap::const_iterator, KnownFileSizeMap::const_iterator> p;
189 p = m_knownSizeMap->equal_range((uint32) in_size);
190 for (KnownFileSizeMap::const_iterator it = p.first; it != p.second; it++) {
191 CKnownFile *cur_file = it->second;
192 if (KnownFileMatches(cur_file, filename, in_date, in_size)) {
193 return cur_file;
196 } else {
197 for (CKnownFileMap::const_iterator it = m_knownFileMap.begin();
198 it != m_knownFileMap.end(); ++it) {
199 CKnownFile *cur_file = it->second;
200 if (KnownFileMatches(cur_file, filename, in_date, in_size)) {
201 return cur_file;
206 return IsOnDuplicates(filename, in_date, in_size);
210 CKnownFile *CKnownFileList::IsOnDuplicates(
211 const CPath& filename,
212 uint32 in_date,
213 uint64 in_size) const
215 if (m_duplicateSizeMap) {
216 std::pair<KnownFileSizeMap::const_iterator, KnownFileSizeMap::const_iterator> p;
217 p = m_duplicateSizeMap->equal_range((uint32) in_size);
218 for (KnownFileSizeMap::const_iterator it = p.first; it != p.second; it++) {
219 CKnownFile *cur_file = it->second;
220 if (KnownFileMatches(cur_file, filename, in_date, in_size)) {
221 return cur_file;
224 } else {
225 for (KnownFileList::const_iterator it = m_duplicateFileList.begin();
226 it != m_duplicateFileList.end(); ++it) {
227 CKnownFile *cur_file = *it;
228 if (KnownFileMatches(cur_file, filename, in_date, in_size)) {
229 return cur_file;
233 return NULL;
237 CKnownFile* CKnownFileList::FindKnownFileByID(const CMD4Hash& hash)
239 wxMutexLocker sLock(list_mut);
241 if (!hash.IsEmpty()) {
242 if (m_knownFileMap.find(hash) != m_knownFileMap.end()) {
243 return m_knownFileMap[hash];
244 } else {
245 return NULL;
248 return NULL;
253 bool CKnownFileList::SafeAddKFile(CKnownFile* toadd, bool afterHashing)
255 bool ret;
257 wxMutexLocker sLock(list_mut);
258 ret = Append(toadd, afterHashing);
260 if (ret) {
261 theApp->searchlist->UpdateSearchFileByHash(toadd->GetFileHash());
263 return ret;
267 bool CKnownFileList::Append(CKnownFile *Record, bool afterHashing)
269 if (Record->GetFileSize() > 0) {
270 const CMD4Hash& tkey = Record->GetFileHash();
271 CKnownFileMap::iterator it = m_knownFileMap.find(tkey);
272 if (it == m_knownFileMap.end()) {
273 m_knownFileMap[tkey] = Record;
274 return true;
275 } else {
276 CKnownFile *existing = it->second;
277 if (KnownFileMatches(Record, existing->GetFileName(), existing->GetLastChangeDatetime(), existing->GetFileSize())) {
278 // The file is already on the list, ignore it.
279 AddDebugLogLineN(logKnownFiles, CFormat(wxT("%s is already on the list")) % Record->GetFileName().GetPrintable());
280 return false;
281 } else if (IsOnDuplicates(Record->GetFileName(), Record->GetLastChangeDatetime(), Record->GetFileSize())) {
282 // The file is on the duplicates list, ignore it.
283 // Should not happen, at least not after hashing. Or why did it get hashed in the first place then?
284 AddDebugLogLineN(logKnownFiles, CFormat(wxT("%s is on the duplicates list")) % Record->GetFileName().GetPrintable());
285 return false;
286 } else {
287 if (afterHashing && existing->GetFileSize() == Record->GetFileSize()) {
288 // We just hashed a "new" shared file and find it's already known under a different name or date.
289 // Guess what - it was probably renamed or touched.
290 // So copy over all properties from the existing known file and just keep name/date.
291 time_t newDate = Record->GetLastChangeDatetime();
292 CPath newName = Record->GetFileName();
293 CMemFile f;
294 existing->WriteToFile(&f);
295 f.Reset();
296 Record->LoadFromFile(&f);
297 Record->SetLastChangeDatetime(newDate);
298 Record->SetFileName(newName);
300 // The file is a duplicated hash. Add THE OLD ONE to the duplicates list.
301 // (This is used when reading the known file list where the duplicates are stored in front.)
302 m_duplicateFileList.push_back(existing);
303 if (theApp->sharedfiles) {
304 // Removing the old kad keywords created with the old filename
305 theApp->sharedfiles->RemoveKeywords(existing);
307 m_knownFileMap[tkey] = Record;
308 return true;
311 } else {
312 AddDebugLogLineN(logGeneral,
313 CFormat(wxT("%s is 0-size, not added")) %
314 Record->GetFileName());
316 return false;
320 // Make an index by size to speed up FindKnownFile
321 // Size modulo 2^32 is enough here
322 void CKnownFileList::PrepareIndex()
324 ReleaseIndex();
325 m_knownSizeMap = new KnownFileSizeMap;
326 for (CKnownFileMap::const_iterator it = m_knownFileMap.begin(); it != m_knownFileMap.end(); it++) {
327 m_knownSizeMap->insert(std::pair<uint32, CKnownFile*>((uint32) it->second->GetFileSize(), it->second));
329 m_duplicateSizeMap = new KnownFileSizeMap;
330 for (KnownFileList::const_iterator it = m_duplicateFileList.begin(); it != m_duplicateFileList.end(); it++) {
331 m_duplicateSizeMap->insert(std::pair<uint32, CKnownFile*>((uint32) (*it)->GetFileSize(), *it));
336 void CKnownFileList::ReleaseIndex()
338 delete m_knownSizeMap;
339 delete m_duplicateSizeMap;
340 m_knownSizeMap = NULL;
341 m_duplicateSizeMap = NULL;
344 // File_checked_for_headers