2 // This file is part of the aMule Project.
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 )
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
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.
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
35 #include <common/Format.h>
38 // This function is inlined for performance
39 inline bool CKnownFileList::KnownFileMatches(
40 CKnownFile
*knownFile
,
41 const CPath
& filename
,
46 (knownFile
->GetLastChangeDatetime() == (time_t)in_date
) &&
47 (knownFile
->GetFileSize() == in_size
) &&
48 (knownFile
->GetFileName() == filename
);
52 CKnownFileList::CKnownFileList()
61 CKnownFileList::~CKnownFileList()
67 bool CKnownFileList::Init()
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.
78 if (!file
.Open(fullpath
)) {
79 AddLogLineM(true, _("WARNING: known.met cannot be opened."));
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."));
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());
103 wxT("Failed to load entry in knownfilelist, file may be corrupt"));
106 AddDebugLogLineM(false, logKnownFiles
, wxT("Finished reading known files"));
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());
119 void CKnownFileList::Save()
121 CFile
file(theApp
->ConfigDir
+ wxT("known.met"), CFile::write
);
122 if (!file
.IsOpened()) {
126 wxMutexLocker
sLock(list_mut
);
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;
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;
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
) {
171 m_knownFileMap
.clear();
173 for (KnownFileList::iterator it
= m_duplicateFileList
.begin();
174 it
!= m_duplicateFileList
.end(); ++it
) {
177 m_duplicateFileList
.clear();
181 CKnownFile
* CKnownFileList::FindKnownFile(
182 const CPath
& filename
,
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
)) {
196 return IsOnDuplicates(filename
, in_date
, in_size
);
200 CKnownFile
*CKnownFileList::IsOnDuplicates(
201 const CPath
& filename
,
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
)) {
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()) {
228 // For the list, we have to iterate to search
229 for (KnownFileList::iterator it
= m_duplicateFileList
.begin();
230 it
!= m_duplicateFileList
.end(); ++it
) {
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
];
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
;
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.
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
;
292 AddDebugLogLineM(false, logGeneral
,
293 CFormat(wxT("%s is 0-size, not added")) %
294 Record
->GetFileName());
300 // File_checked_for_headers