Upstream tarball 9452
[amule.git] / src / KnownFileList.cpp
blobdb50d88a8fbdd3e7e2106c0287119476b43d9f87
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 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 <common/Format.h>
38 // This function is inlined for performance
39 inline bool CKnownFileList::KnownFileMatches(
40 CKnownFile *knownFile,
41 const CPath& filename,
42 uint32 in_date,
43 uint64 in_size) const
45 return
46 (knownFile->GetLastChangeDatetime() == (time_t)in_date) &&
47 (knownFile->GetFileSize() == in_size) &&
48 (knownFile->GetFileName() == filename);
52 CKnownFileList::CKnownFileList()
54 accepted = 0;
55 requested = 0;
56 transferred = 0;
57 Init();
61 CKnownFileList::~CKnownFileList()
63 Clear();
67 bool CKnownFileList::Init()
69 CFile file;
71 CPath fullpath = CPath(theApp->ConfigDir + wxT("known.met"));
72 if (!fullpath.FileExists()) {
73 // This is perfectly normal. The file was probably either
74 // deleted, or this is the first time running aMule.
75 return false;
78 if (!file.Open(fullpath)) {
79 AddLogLineM(true, _("WARNING: known.met cannot be opened."));
80 return false;
83 try {
84 uint8 version = file.ReadUInt8();
85 if ((version != MET_HEADER) && (version != MET_HEADER_WITH_LARGEFILES)) {
86 AddLogLineM(true, _("WARNING: Known file list corrupted, contains invalid header."));
87 return false;
90 wxMutexLocker sLock(list_mut);
91 uint32 RecordsNumber = file.ReadUInt32();
92 AddDebugLogLineM(false, logKnownFiles,
93 wxString::Format(wxT("Reading %i known files from file format 0x%2.2x."),
94 RecordsNumber, version));
95 for (uint32 i = 0; i < RecordsNumber; i++) {
96 std::auto_ptr<CKnownFile> record(new CKnownFile());
97 if (record->LoadFromFile(&file)) {
98 AddDebugLogLineM(false, logKnownFiles,
99 CFormat(wxT("Known file read: %s")) % record->GetFileName());
100 Append(record.release());
101 } else {
102 AddLogLineM(true,
103 wxT("Failed to load entry in knownfilelist, file may be corrupt"));
106 AddDebugLogLineM(false, logKnownFiles, wxT("Finished reading known files"));
108 return true;
109 } catch (const CInvalidPacket& e) {
110 AddLogLineM(true, wxT("Invalid entry in knownfilelist, file may be corrupt: ") + e.what());
111 } catch (const CSafeIOException& e) {
112 AddLogLineM(true, CFormat(_("IO error while reading known.met file: %s")) % e.what());
115 return false;
119 void CKnownFileList::Save()
121 CFile file(theApp->ConfigDir + wxT("known.met"), CFile::write);
122 if (!file.IsOpened()) {
123 return;
126 wxMutexLocker sLock(list_mut);
128 try {
129 // Kry - This is the version, but we don't know it till
130 // we know if any largefile is saved. This allows the list
131 // to be compatible with previous versions.
132 bool bContainsAnyLargeFiles = false;
133 file.WriteUInt8(0);
135 file.WriteUInt32(m_knownFileMap.size() + m_duplicateFileList.size());
137 // Duplicates handling. Duplicates needs to be saved first,
138 // since it is the last entry that gets used.
139 KnownFileList::iterator itDup = m_duplicateFileList.begin();
140 for ( ; itDup != m_duplicateFileList.end(); ++itDup ) {
141 (*itDup)->WriteToFile(&file);
142 if ((*itDup)->IsLargeFile()) {
143 bContainsAnyLargeFiles = true;
147 CKnownFileMap::iterator it = m_knownFileMap.begin();
148 for (; it != m_knownFileMap.end(); ++it) {
149 it->second->WriteToFile(&file);
150 if (it->second->IsLargeFile()) {
151 bContainsAnyLargeFiles = true;
155 file.Seek(0);
156 file.WriteUInt8(bContainsAnyLargeFiles ? MET_HEADER_WITH_LARGEFILES : MET_HEADER);
157 } catch (const CIOFailureException& e) {
158 AddLogLineM(true, CFormat(_("Error while saving known.met file: %s")) % e.what());
163 void CKnownFileList::Clear()
165 wxMutexLocker sLock(list_mut);
167 for (CKnownFileMap::iterator it = m_knownFileMap.begin();
168 it != m_knownFileMap.end(); ++it) {
169 delete it->second;
171 m_knownFileMap.clear();
173 for (KnownFileList::iterator it = m_duplicateFileList.begin();
174 it != m_duplicateFileList.end(); ++it) {
175 delete *it;
177 m_duplicateFileList.clear();
181 CKnownFile* CKnownFileList::FindKnownFile(
182 const CPath& filename,
183 time_t in_date,
184 uint64 in_size)
186 wxMutexLocker sLock(list_mut);
188 for (CKnownFileMap::const_iterator it = m_knownFileMap.begin();
189 it != m_knownFileMap.end(); ++it) {
190 CKnownFile *cur_file = it->second;
191 if (KnownFileMatches(cur_file, filename, in_date, in_size)) {
192 return cur_file;
196 return IsOnDuplicates(filename, in_date, in_size);
200 CKnownFile *CKnownFileList::IsOnDuplicates(
201 const CPath& filename,
202 uint32 in_date,
203 uint64 in_size) const
205 for (KnownFileList::const_iterator it = m_duplicateFileList.begin();
206 it != m_duplicateFileList.end(); ++it) {
207 CKnownFile *cur_file = *it;
208 if (KnownFileMatches(cur_file, filename, in_date, in_size)) {
209 return cur_file;
212 return NULL;
216 bool CKnownFileList::IsKnownFile(const CKnownFile *file)
218 wxCHECK(file, false);
220 wxMutexLocker sLock(list_mut);
222 // For the map, search with the key
223 const CMD4Hash &key = file->GetFileHash();
224 CKnownFileMap::const_iterator itMap = m_knownFileMap.find(key);
225 if (itMap != m_knownFileMap.end()) {
226 return true;
228 // For the list, we have to iterate to search
229 for (KnownFileList::iterator it = m_duplicateFileList.begin();
230 it != m_duplicateFileList.end(); ++it) {
231 if (*it == file) {
232 return true;
235 return false;
239 CKnownFile* CKnownFileList::FindKnownFileByID(const CMD4Hash& hash)
241 wxMutexLocker sLock(list_mut);
243 if (!hash.IsEmpty()) {
244 if (m_knownFileMap.find(hash) != m_knownFileMap.end()) {
245 return m_knownFileMap[hash];
246 } else {
247 return NULL;
250 return NULL;
255 bool CKnownFileList::SafeAddKFile(CKnownFile* toadd)
257 wxMutexLocker sLock(list_mut);
258 return Append(toadd);
262 bool CKnownFileList::Append(CKnownFile *Record)
264 if (Record->GetFileSize() > 0) {
265 const CMD4Hash& tkey = Record->GetFileHash();
266 CKnownFileMap::iterator it = m_knownFileMap.find(tkey);
267 if (it == m_knownFileMap.end()) {
268 m_knownFileMap[tkey] = Record;
269 return true;
270 } else {
271 it->second;
272 time_t in_date = it->second->GetLastChangeDatetime();
273 uint64 in_size = it->second->GetFileSize();
274 CPath filename = it->second->GetFileName();
275 if (KnownFileMatches(Record, filename, in_date, in_size) ||
276 IsOnDuplicates(filename, in_date, in_size)) {
277 // The file is already on the list, ignore it.
278 return false;
279 } else {
280 // The file is a duplicated hash. Add THE OLD ONE to the duplicates list.
281 m_duplicateFileList.push_back(m_knownFileMap[tkey]);
282 // Is this thread-safe? If John is not sure and I'm not sure either...
283 if (theApp->sharedfiles) {
284 // Removing the old kad keywords created with the old filename
285 theApp->sharedfiles->RemoveKeywords(it->second);
287 m_knownFileMap[tkey] = Record;
288 return true;
291 } else {
292 AddDebugLogLineM(false, logGeneral,
293 CFormat(wxT("%s is 0-size, not added")) %
294 Record->GetFileName());
296 return false;
300 // File_checked_for_headers