Beispiel #1
0
bool CKnownFileList::LoadKnownFiles()
{
	CString fullpath = thePrefs.GetMuleDirectory(EMULE_CONFIGDIR);
	fullpath.Append(KNOWN_MET_FILENAME);
	CSafeBufferedFile file;
	CFileException fexp;
	if (!file.Open(fullpath,CFile::modeRead|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyWrite, &fexp)){
		if (fexp.m_cause != CFileException::fileNotFound){
			CString strError(_T("Failed to load ") KNOWN_MET_FILENAME _T(" file"));
			TCHAR szError[MAX_CFEXP_ERRORMSG];
			if (fexp.GetErrorMessage(szError, ARRSIZE(szError))){
				strError += _T(" - ");
				strError += szError;
			}
			LogError(LOG_STATUSBAR, _T("%s"), strError);
		}
		return false;
	}
	setvbuf(file.m_pStream, NULL, _IOFBF, 16384);

	CKnownFile* pRecord = NULL;
	try {
		uint8 header = file.ReadUInt8();
		if (header != MET_HEADER && header != MET_HEADER_I64TAGS){
			file.Close();
			LogError(LOG_STATUSBAR, GetResString(IDS_ERR_SERVERMET_BAD));
			return false;
		}
		AddDebugLogLine(false, _T("Known.met file version is %u (%s support 64bit tags)"), header, (header == MET_HEADER) ? _T("doesn't") : _T("does")); 

		UINT RecordsNumber = file.ReadUInt32();
		for (UINT i = 0; i < RecordsNumber; i++) {
			pRecord = new CKnownFile();
			if (!pRecord->LoadFromFile(&file)){
				TRACE(_T("*** Failed to load entry %u (name=%s  hash=%s  size=%I64u  parthashs=%u expected parthashs=%u) from known.met\n"), i, 
					pRecord->GetFileName(), md4str(pRecord->GetFileHash()), pRecord->GetFileSize(), pRecord->GetHashCount(), pRecord->GetED2KPartHashCount());
				delete pRecord;
				pRecord = NULL;
				continue;
			}
			SafeAddKFile(pRecord);
			pRecord = NULL;
		}
		file.Close();
	}
	catch(CFileException* error){
		if (error->m_cause == CFileException::endOfFile)
			LogError(LOG_STATUSBAR, GetResString(IDS_ERR_SERVERMET_BAD));
		else{
			TCHAR buffer[MAX_CFEXP_ERRORMSG];
			error->GetErrorMessage(buffer, ARRSIZE(buffer));
			LogError(LOG_STATUSBAR, GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer);
		}
		error->Delete();
		delete pRecord;
		return false;
	}

	return true;
}
BOOL CCommentDialog::OnSetActive()
{
	if (!CResizablePage::OnSetActive())
		return FALSE;
	if (m_bDataChanged)
	{
		bool bContainsSharedKnownFile = false;;
		int iRating = -1;
		m_bMergedComment = false;
		CString strComment;
		for (int i = 0; i < m_paFiles->GetSize(); i++)
		{
			if (!(*m_paFiles)[i]->IsKindOf(RUNTIME_CLASS(CKnownFile)))
				continue;
			CKnownFile* file = STATIC_DOWNCAST(CKnownFile, (*m_paFiles)[i]);
			// we actually could show, add and even search for comments on kad for known but not shared files,
			// but we don't publish coments entered by the user if the file is not shared (which might be changed at some point)
			// so make sure we don't let him think he can comment and disable the dialog for such files
			if (theApp.sharedfiles->GetFileByID(file->GetFileHash()) == NULL)
				continue;
			bContainsSharedKnownFile = true;
			if (i == 0)
			{
				strComment = file->GetFileComment();
				iRating = file->GetFileRating();
			}
			else
			{
				if (!m_bMergedComment && strComment.Compare(file->GetFileComment()) != 0)
				{
					strComment.Empty();
					m_bMergedComment = true;
				}
				if (iRating != -1 && (UINT)iRating != file->GetFileRating())
					iRating = -1;
			}
		}
		m_bSelf = true;
		SetDlgItemText(IDC_CMT_TEXT, strComment);
		((CEdit*)GetDlgItem(IDC_CMT_TEXT))->SetLimitText(MAXFILECOMMENTLEN);
		m_ratebox.SetCurSel(iRating);
		m_bSelf = false;
		EnableDialog(bContainsSharedKnownFile);

		m_bDataChanged = false;

		RefreshData();
	}

	return TRUE;
}
BOOL CCommentDialog::OnApply()
{
	if (m_bEnabled && !m_bDataChanged)
	{
	    CString strComment;
	    GetDlgItem(IDC_CMT_TEXT)->GetWindowText(strComment);
	    int iRating = m_ratebox.GetCurSel();
	    for (int i = 0; i < m_paFiles->GetSize(); i++)
	    {
			if (!(*m_paFiles)[i]->IsKindOf(RUNTIME_CLASS(CKnownFile)))
				continue;
		    CKnownFile* file = STATIC_DOWNCAST(CKnownFile, (*m_paFiles)[i]);
			if (theApp.sharedfiles->GetFileByID(file->GetFileHash()) == NULL)
				continue;
		    if (!strComment.IsEmpty() || !m_bMergedComment)
			    file->SetFileComment(strComment);
		    if (iRating != -1)
			    file->SetFileRating(iRating);
	    }
	}
	return CResizablePage::OnApply();
}
Beispiel #4
0
bool CUpDownClient::ProcessPeerCacheQuery(const uchar* packet, UINT size)
{
	const bool bDebug = (thePrefs.GetDebugClientTCPLevel() > 0);
	if (bDebug)
		DebugRecv("OP_PeerCacheQuery", this);

	if (socket == NULL){
		ASSERT(0);
		return false;
	}

	CSafeMemFile dataRecv(packet, size);
	uint8 uPCVersion = dataRecv.ReadUInt8();
	if (uPCVersion != PCPCK_VERSION){
		if (bDebug)
			Debug(_T("   ***Invalid packet version: 0x%02x\n"), uPCVersion);
		ASSERT(0);
		return false;
	}
	uint8 uPCOpcode = dataRecv.ReadUInt8();
	if (uPCOpcode != PCOP_REQ){
		if (bDebug)
			Debug(_T("   ***Invalid packet opcode: 0x%02x\n"), uPCOpcode);
		ASSERT(0);
		return false;
	}

	uint32 uCacheIP = 0;
	uint16 uCachePort = 0;
	uint32 uPushId = 0;
	uchar aucFileHash[16];
	uint32 uRemoteIP = 0;
	md4clr(aucFileHash);

	CString strInfo;
	UINT uTags = dataRecv.ReadUInt8();
	while (uTags--)
	{
		CTag tag(&dataRecv, GetUnicodeSupport()!=utf8strNone);
		if (tag.GetNameID() == PCTAG_CACHEIP && tag.IsInt())
		{
			uCacheIP = tag.GetInt();
			if (bDebug)
				strInfo.AppendFormat(_T("  CacheIP=%s"), ipstr(uCacheIP));
		}
		else if (tag.GetNameID() == PCTAG_CACHEPORT && tag.IsInt())
		{
			uCachePort = (uint16)tag.GetInt();
			if (bDebug)
				strInfo.AppendFormat(_T("  CachePort=%u"), uCachePort);
		}
		else if (tag.GetNameID() == PCTAG_PUSHID && tag.IsInt())
		{
			uPushId = tag.GetInt();
			if (bDebug)
				strInfo.AppendFormat(_T("  PushId=%u"), uPushId);
		}
		else if (tag.GetNameID() == PCTAG_FILEID && tag.IsHash() && tag.GetHash() != NULL)
		{
			md4cpy(aucFileHash, tag.GetHash());
			if (bDebug)
				strInfo.AppendFormat(_T("  FileId=%s"), md4str(aucFileHash));
		}
		else if (tag.GetNameID() == PCTAG_PUBLICIP && tag.IsInt())
		{
			uRemoteIP = tag.GetInt();
			if (bDebug)
				strInfo.AppendFormat(_T("  PublicIP=%s"), ipstr(uRemoteIP));
		}
		else
		{
			if (bDebug)
				strInfo.AppendFormat(_T("  ***UnkTag: %s"), tag.GetFullInfo());
			ASSERT(0);
		}
	}

	if (bDebug)
	{
		if (dataRecv.GetPosition() < dataRecv.GetLength())
			strInfo.AppendFormat(_T("  ***AddData: %u bytes"), (UINT)(dataRecv.GetLength() - dataRecv.GetPosition()));
		Debug(_T("%s\n"), strInfo);
	}

	if (uCacheIP == 0 || uCachePort == 0 || uPushId == 0 || isnulmd4(aucFileHash)){
		if (thePrefs.GetVerbose())
			AddDebugLogLine(false, _T("Invalid PeerCacheQuery; %s"), DbgGetClientInfo());
		return false;
	}

	CKnownFile* pUploadFile = theApp.sharedfiles->GetFileByID(aucFileHash);
	if (pUploadFile == NULL){
		if (thePrefs.GetVerbose())
			AddDebugLogLine(false, _T("PeerCacheQuery reqfile does not match ed2k reqfile; %s"), DbgGetClientInfo());
		return false;
	}

	if (m_pPCUpSocket != NULL)
	{
        SetPeerCacheUpState(PCUS_NONE);
		m_pPCUpSocket->Safe_Delete();
		ASSERT( m_pPCUpSocket == NULL );
	}
	m_pPCUpSocket = new CPeerCacheUpSocket(this);
	m_pPCUpSocket->SetTimeOut(GetPeerCacheSocketUploadTimeout());
	m_pPCUpSocket->Create();

	SOCKADDR_IN sockAddr = {0};
	sockAddr.sin_family = AF_INET;
	sockAddr.sin_port = htons(uCachePort);
	sockAddr.sin_addr.S_un.S_addr = uCacheIP;
	//Try to always tell the socket to WaitForOnConnect before you call Connect.
	m_pPCUpSocket->WaitForOnConnect();
	m_pPCUpSocket->Connect((SOCKADDR*)&sockAddr, sizeof sockAddr);

	CStringA strPCRequest;
	strPCRequest.AppendFormat("GIVE %u\r\n", uPushId);

	if (thePrefs.GetDebugClientTCPLevel() > 0){
		DebugSend("PeerCache-GIVE", this, pUploadFile->GetFileHash());
		Debug(_T("  %hs\n"), strPCRequest);
	}
	
	CRawPacket* pHttpPacket = new CRawPacket(strPCRequest);
	theStats.AddUpDataOverheadFileRequest(pHttpPacket->size);
	m_pPCUpSocket->SendPacket(pHttpPacket);
	m_pPCUpSocket->SetHttpState(HttpStateRecvExpected);
	m_bPeerCacheUpHit = false;
	SetPeerCacheUpState(PCUS_WAIT_CACHE_REPLY);
	//theApp.uploadBandwidthThrottler->AddToStandardList(0, m_pPCUpSocket);

	CSafeMemFile dataSend(128);
	dataSend.WriteUInt8(PCPCK_VERSION);
	dataSend.WriteUInt8(PCOP_RES);
	dataSend.WriteUInt8(3);
	CTag tagPushId(PCTAG_PUSHID, uPushId);
	tagPushId.WriteNewEd2kTag(&dataSend);
	CTag tagPublicIP(PCTAG_PUBLICIP, theApp.GetPublicIP());
	tagPublicIP.WriteNewEd2kTag(&dataSend);
	CTag tagFileId(PCTAG_FILEID, (BYTE*)aucFileHash);
	tagFileId.WriteNewEd2kTag(&dataSend);
	
	if (thePrefs.GetDebugClientTCPLevel() > 0){
		DebugSend("OP__PeerCacheAnswer", this, aucFileHash);
		Debug(_T("  PushId=%u  PublicIP=%s  FileId=%s\n"), tagPushId.GetInt(), ipstr(tagPublicIP.GetInt()), md4str(tagFileId.GetHash()));
	}
	
	Packet* pEd2kPacket = new Packet(&dataSend, OP_EMULEPROT, OP_PEERCACHE_ANSWER);
	theStats.AddUpDataOverheadFileRequest(pEd2kPacket->size);
	socket->SendPacket(pEd2kPacket);
	return true;
}
int CAICHSyncThread::Run()
{
	if ( !theApp.emuledlg->IsRunning() )
		return 0;

	// we collect all masterhashs which we find in the known2.met and store them in a list
	CList<CAICHHash> liKnown2Hashs;
	CString fullpath=thePrefs.GetConfigDir();
	fullpath.Append(KNOWN2_MET_FILENAME);
	CSafeFile file;
	CFileException fexp;
	uint32 nLastVerifiedPos = 0;
	if (!file.Open(fullpath,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyNone, &fexp)){
		if (fexp.m_cause != CFileException::fileNotFound){
			CString strError(_T("Failed to load ") KNOWN2_MET_FILENAME _T(" file"));
			TCHAR szError[MAX_CFEXP_ERRORMSG];
			if (fexp.GetErrorMessage(szError, ARRSIZE(szError))){
				strError += _T(" - ");
				strError += szError;
			}
			LogError(LOG_STATUSBAR, _T("%s"), strError);
		}
		return false;
	}
	try {
		//setvbuf(file.m_pStream, NULL, _IOFBF, 16384);
		uint32 nExistingSize = file.GetLength();
		uint16 nHashCount;
		while (file.GetPosition() < nExistingSize){
			liKnown2Hashs.AddTail(CAICHHash(&file));
			nHashCount = file.ReadUInt16();
			if (file.GetPosition() + nHashCount*HASHSIZE > nExistingSize){
				AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName());
			}
			// skip the rest of this hashset
			file.Seek(nHashCount*HASHSIZE, CFile::current);
			nLastVerifiedPos = file.GetPosition();
		}
	}
	catch(CFileException* error){
		if (error->m_cause == CFileException::endOfFile){
			LogError(LOG_STATUSBAR,GetResString(IDS_ERR_SERVERMET_BAD));
			// truncate the file to the size to the last verified valid pos
			try{
				file.SetLength(nLastVerifiedPos);
			}
			catch(CFileException* error2){
				error2->Delete();
			}
		}
		else{
			TCHAR buffer[MAX_CFEXP_ERRORMSG];
			error->GetErrorMessage(buffer, ARRSIZE(buffer));
			LogError(LOG_STATUSBAR,GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer);
		}
		error->Delete();
		return false;
	}
	file.Close();

	// now we check that all files which are in the sharedfilelist have a corresponding hash in out list
	// those how don'T are added to the hashinglist
	for (uint32 i = 0; i < theApp.sharedfiles->GetCount(); i++){
		CKnownFile* pCurFile = theApp.sharedfiles->GetFileByIndex(i);
		if (pCurFile != NULL && !pCurFile->IsPartFile() ){
			if (theApp.emuledlg==NULL || !theApp.emuledlg->IsRunning()) // in case of shutdown while still hashing
				return 0;
			if (pCurFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE){
				bool bFound = false;
				for (POSITION pos = liKnown2Hashs.GetHeadPosition();pos != 0;)
				{
					if (liKnown2Hashs.GetNext(pos) == pCurFile->GetAICHHashset()->GetMasterHash()){
						bFound = true;
#ifdef _DEBUG
						// in debugmode we load and verify all hashsets
						ASSERT( pCurFile->GetAICHHashset()->LoadHashSet() );
//			 			pCurFile->GetAICHHashset()->DbgTest();
						pCurFile->GetAICHHashset()->FreeHashSet();
#endif
						break;
					}
				}
				if (bFound) // hashset is available, everything fine with this file
					continue;
			}
			pCurFile->GetAICHHashset()->SetStatus(AICH_ERROR);
			m_liToHash.AddTail(pCurFile);
		}
	}
	// warn the user if he just upgraded
	if (thePrefs.IsFirstStart() && !m_liToHash.IsEmpty()){
		LogWarning(GetResString(IDS_AICH_WARNUSER));
	}

	if (!m_liToHash.IsEmpty()){
		AddLogLine(true, GetResString(IDS_AICH_SYNCTOTAL), m_liToHash.GetCount() );	// I18n: ThreadSafeLog
		theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(m_liToHash.GetCount());
		// let first all normal hashing be done before starting out synchashing
		CSingleLock sLock1(&theApp.hashing_mut); // only one filehash at a time
		while (theApp.sharedfiles->GetHashingCount() != 0){
			Sleep(100);
		}
		sLock1.Lock();
		uint32 cDone = 0;
		for (POSITION pos = m_liToHash.GetHeadPosition();pos != 0; cDone++)
		{
			if (theApp.emuledlg==NULL || !theApp.emuledlg->IsRunning()){ // in case of shutdown while still hashing
				return 0;
			}
			theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(m_liToHash.GetCount()-cDone);
			if (theApp.emuledlg->sharedfileswnd->sharedfilesctrl.m_hWnd != NULL)
				theApp.emuledlg->sharedfileswnd->sharedfilesctrl.ShowFilesCount();
			CKnownFile* pCurFile = m_liToHash.GetNext(pos);
			// just to be sure that the file hasnt been deleted lately
			if (!(theApp.knownfiles->IsKnownFile(pCurFile) && theApp.sharedfiles->GetFileByID(pCurFile->GetFileHash())) )
				continue;
			AddLogLine(false, GetResString(IDS_AICH_CALCFILE), pCurFile->GetFileName());	// I18n: ThreadSafeLog
			if(!pCurFile->CreateAICHHashSetOnly())
				// [TPT] - WebCache 
				if(thePrefs.GetLogICHEvents()) //JP log ICH events
				AddDebugLogLine(false, _T("Failed to create AICH Hashset while sync. for file %s"), pCurFile->GetFileName());	// I18n: ThreadSafeLog
		}

		theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(0);
		if (theApp.emuledlg->sharedfileswnd->sharedfilesctrl.m_hWnd != NULL)
			theApp.emuledlg->sharedfileswnd->sharedfilesctrl.ShowFilesCount();
		sLock1.Unlock();
	}
	// [TPT] - WebCache 
	if(thePrefs.GetLogICHEvents()) //JP log ICH events
	AddDebugLogLine(false, _T("AICHSyncThread finished"));	// I18n: ThreadSafeLog
	return 0;
}
void CSharedFilesCtrl::OnDrawItem( int item, wxDC* dc, const wxRect& rect, const wxRect& rectHL, bool highlighted )
{
	CKnownFile *file = (CKnownFile*)GetItemData(item);
	wxASSERT( file );

	if ( highlighted ) {
		CMuleColour newcol(GetFocus() ? wxSYS_COLOUR_HIGHLIGHT : wxSYS_COLOUR_BTNSHADOW);	
		dc->SetBackground(newcol.Blend(125).GetBrush());
		dc->SetTextForeground( CMuleColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
		// The second blending goes over the first one.
		dc->SetPen(newcol.Blend(65).GetPen());
	} else {
		dc->SetBackground( CMuleColour(wxSYS_COLOUR_LISTBOX).GetBrush() );
		dc->SetTextForeground(CMuleColour(wxSYS_COLOUR_WINDOWTEXT));
		dc->SetPen(*wxTRANSPARENT_PEN);
	}
	
	dc->SetBrush(dc->GetBackground());
	dc->DrawRectangle(rectHL);
	dc->SetPen(*wxTRANSPARENT_PEN);

	// Offset based on the height of the fonts
	const int textVOffset = ( rect.GetHeight() - dc->GetCharHeight() ) / 2;
	// Empty space to each side of a column
	const int SPARE_PIXELS_HORZ	= 4;

	// The leftmost position of the current column
	int columnLeft = 0;
	
	for ( int i = 0; i < GetColumnCount(); ++i ) {
		const int columnWidth = GetColumnWidth(i);

		if (columnWidth > 2*SPARE_PIXELS_HORZ) {
			wxRect columnRect(
				columnLeft + SPARE_PIXELS_HORZ, rect.y,
				columnWidth - 2 * SPARE_PIXELS_HORZ, rect.height);
			
			wxDCClipper clipper(*dc, columnRect);
			
			wxString textBuffer;
			switch ( i ) {
				case ID_SHARED_COL_NAME:
					textBuffer = file->GetFileName().GetPrintable();

					if (file->GetFileRating() || file->GetFileComment().Length()) {
						int image = Client_CommentOnly_Smiley;
						if (file->GetFileRating()) {
							image = Client_InvalidRating_Smiley + file->GetFileRating() - 1;
						}	
							
						wxASSERT(image >= Client_InvalidRating_Smiley);
						wxASSERT(image <= Client_CommentOnly_Smiley);

						int imgWidth = 16;
						
						theApp->amuledlg->m_imagelist.Draw(image, *dc, columnRect.x,
								columnRect.y + 1, wxIMAGELIST_DRAW_TRANSPARENT);

						// Move the text to the right
						columnRect.x += (imgWidth + 4);
					}

					break;
				
				case ID_SHARED_COL_SIZE:
					textBuffer = CastItoXBytes(file->GetFileSize());
					break;

				case ID_SHARED_COL_TYPE:
					textBuffer = GetFiletypeByName(file->GetFileName());
					break;

				case ID_SHARED_COL_PRIO:
					textBuffer = PriorityToStr(file->GetUpPriority(), file->IsAutoUpPriority());
					break;

				case ID_SHARED_COL_ID:
					textBuffer = file->GetFileHash().Encode();
					break;
				
				case ID_SHARED_COL_REQ:
					textBuffer = CFormat(wxT("%u (%u)"))
							% file->statistic.GetRequests()
							% file->statistic.GetAllTimeRequests();
					break;

				case ID_SHARED_COL_AREQ:
					textBuffer = CFormat(wxT("%u (%u)"))
							% file->statistic.GetAccepts()
							% file->statistic.GetAllTimeAccepts();
					break;

				case ID_SHARED_COL_TRA:
					textBuffer = CastItoXBytes(file->statistic.GetTransferred())
						+ wxT(" (") + CastItoXBytes(file->statistic.GetAllTimeTransferred()) + wxT(")");
					break;
					
				case ID_SHARED_COL_RTIO:
					textBuffer = CFormat(wxT("%.2f")) %	((double)file->statistic.GetAllTimeTransferred() / file->GetFileSize());
					break;
				
				case ID_SHARED_COL_PART:
					if ( file->GetPartCount() ) {
						wxRect barRect(columnRect.x, columnRect. y + 1, 
							columnRect.width, columnRect.height - 2);
						
						DrawAvailabilityBar(file, dc, barRect);
					}
					break;
				
				case ID_SHARED_COL_CMPL:
					if ( file->m_nCompleteSourcesCountLo == 0 ) {
						if ( file->m_nCompleteSourcesCountHi ) {
							textBuffer = CFormat(wxT("< %u")) % file->m_nCompleteSourcesCountHi;
						} else {
							textBuffer = wxT("0");
						}
					} else if (file->m_nCompleteSourcesCountLo == file->m_nCompleteSourcesCountHi) {
						textBuffer = CFormat(wxT("%u")) % file->m_nCompleteSourcesCountLo;
					} else {
						textBuffer = CFormat(wxT("%u - %u")) % file->m_nCompleteSourcesCountLo % file->m_nCompleteSourcesCountHi;
					}
					
					break;				
				
				case ID_SHARED_COL_PATH:
					if ( file->IsPartFile() ) {
						textBuffer = _("[PartFile]");
					} else {
						textBuffer = file->GetFilePath().GetPrintable();
					}
			}

			if (!textBuffer.IsEmpty()) {
				dc->DrawText(textBuffer, columnRect.x, columnRect.y + textVOffset);
			}
		}

		// Move to the next column
		columnLeft += columnWidth;
	}
}
Beispiel #7
0
bool CKnownFileList::SafeAddKFile(CKnownFile* toadd)
{
	bool bRemovedDuplicateSharedFile = false;
	CCKey key(toadd->GetFileHash());
	CKnownFile* pFileInMap;
	if (m_Files_map.Lookup(key, pFileInMap))
	{
		TRACE(_T("%hs: Already in known list:   %s %I64u \"%s\"\n"), __FUNCTION__, md4str(pFileInMap->GetFileHash()), pFileInMap->GetFileSize(), pFileInMap->GetFileName());
		TRACE(_T("%hs: Old entry replaced with: %s %I64u \"%s\"\n"), __FUNCTION__, md4str(toadd->GetFileHash()), toadd->GetFileSize(), toadd->GetFileName());

		// if we hash files which are already in known file list and add them later (when the hashing thread is finished),
		// we can not delete any already available entry from known files list. that entry can already be used by the
		// shared file list -> crash.

		m_Files_map.RemoveKey(CCKey(pFileInMap->GetFileHash()));
		m_mapKnownFilesByAICH.RemoveKey(pFileInMap->GetAICHHashset()->GetMasterHash());
		//This can happen in a couple situations..
		//File was renamed outside of eMule.. 
		//A user decided to redownload a file he has downloaded and unshared..
		//RemovingKeyWords I believe is not thread safe if I'm looking at this right.
		//Not sure of a good solution yet..
		if (theApp.sharedfiles)
		{
#if 0
			// This may crash the client because of dangling ptr in shared files ctrl.
			// This may happen if a file is re-shared which is also currently downloaded.
			// After the file was downloaded (again) there is a dangl. ptr in shared files 
			// ctrl.
			// Actually that's also wrong in some cases: Keywords are not always removed
			// because the wrong ptr is used to search for in keyword publish list.
			theApp.sharedfiles->RemoveKeywords(pFileInMap);
#else
			// This solves the problem with dangl. ptr in shared files ctrl,
			// but creates a new bug. It may lead to unshared files! Even 
			// worse it may lead to files which are 'shared' in GUI but 
			// which are though not shared 'logically'.
			//
			// To reduce the harm, remove the file from shared files list, 
			// only if really needed. Right now this 'harm' applies for files
			// which are re-shared and then completed (again) because they were
			// also in download queue (they were added there when the already
			// available file was not in shared file list).
			if (theApp.sharedfiles->IsFilePtrInList(pFileInMap))
				bRemovedDuplicateSharedFile = theApp.sharedfiles->RemoveFile(pFileInMap);
#endif
			ASSERT( !theApp.sharedfiles->IsFilePtrInList(pFileInMap) );
		}
		//Double check to make sure this is the same file as it's possible that a two files have the same hash.
		//Maybe in the furture we can change the client to not just use Hash as a key throughout the entire client..
		ASSERT( toadd->GetFileSize() == pFileInMap->GetFileSize() );
		ASSERT( toadd != pFileInMap );
		if (toadd->GetFileSize() == pFileInMap->GetFileSize())
			toadd->statistic.MergeFileStats(&pFileInMap->statistic);

		ASSERT( theApp.sharedfiles==NULL || !theApp.sharedfiles->IsFilePtrInList(pFileInMap) );
		ASSERT( theApp.downloadqueue==NULL || !theApp.downloadqueue->IsPartFile(pFileInMap) );

		// Quick fix: If we downloaded already downloaded files again and if those files all had the same file names
		// and were renamed during file completion, we have a pending ptr in transfer window.
		if (theApp.emuledlg && theApp.emuledlg->transferwnd && theApp.emuledlg->transferwnd->downloadlistctrl.m_hWnd)
			theApp.emuledlg->transferwnd->downloadlistctrl.RemoveFile((CPartFile*)pFileInMap);

		delete pFileInMap;
	}
	m_Files_map.SetAt(key, toadd);
	if (bRemovedDuplicateSharedFile) {
		theApp.sharedfiles->SafeAddKFile(toadd);
	}
	if (toadd->GetAICHHashset()->HasValidMasterHash())
		m_mapKnownFilesByAICH.SetAt(toadd->GetAICHHashset()->GetMasterHash(), toadd);
	return true;
}
Beispiel #8
0
BOOL CUpdateInfo::ClearUpdateHistory(const uchar * hashkey)//清除历史升级任务
{
	for (int i = 0; i < CGlobalVariable::sharedfiles->GetCount(); i++)
	{
		CKnownFile* file = CGlobalVariable::sharedfiles->GetFileByIndex(i);
		CPartFile* pPartFile;

		try
		{
			//共享列表中是否有
			if(file)
			{
				if ( IsUpdateTask( file->GetFilePath() ) && file->GetFileHash() != hashkey )
				{
					if(file->IsPartFile())
					{
						//共享列表有,但未下载完,移除
						pPartFile = DYNAMIC_DOWNCAST(CPartFile,file);
						if( pPartFile )
						{
							pPartFile->DeleteFile();
						}
					}
					else
					{
						//共享列表有,已经下载完成未安装,移除
						DeleteFile(file->GetFilePath());
						theApp.emuledlg->sharedfileswnd->sharedfilesctrl.RemoveFile(file);
						CGlobalVariable::sharedfiles->RemoveFile(file);

						CGlobalVariable::filemgr.RemoveFileItem(file);
					}
				}
				else
					continue;
			}
		}
		catch (CException* e)
		{
			e->Delete();
			//return FALSE;
		}
	}

	for (int i = 0; i < CGlobalVariable::downloadqueue->GetFileCount(); i++)
	{
		CPartFile* pFile = CGlobalVariable::downloadqueue->GetFileByIndex(i);
		try
		{
			if (pFile)
			{
				if ( IsUpdateTask( pFile->GetFilePath() ) && pFile->GetFileHash() != hashkey )
				{
					//共享列表没有,但未下载完,移除
					pFile->DeleteFile();
				}
			}
		}
		catch (CException* e)
		{
			e->Delete();
			//return FALSE;
		}
	}

	return TRUE;
}
int CAICHSyncThread::Run()
{
	if ( !theApp.emuledlg->IsRunning() )
		return 0;
	// we need to keep a lock on this file while the thread is running
	CSingleLock lockKnown2Met(&CAICHHashSet::m_mutKnown2File);
	lockKnown2Met.Lock();
	
	// we collect all masterhashs which we find in the known2.met and store them in a list
	CList<CAICHHash> liKnown2Hashs;
	CString fullpath=thePrefs.GetConfigDir();
	fullpath.Append(KNOWN2_MET_FILENAME);
	CSafeFile file;
	CFileException fexp;
	uint32 nLastVerifiedPos = 0;

	if (!file.Open(fullpath,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyNone, &fexp)){
		if (fexp.m_cause != CFileException::fileNotFound){
			CString strError(_T("Failed to load ") KNOWN2_MET_FILENAME _T(" file"));
			TCHAR szError[MAX_CFEXP_ERRORMSG];
			if (fexp.GetErrorMessage(szError, ARRSIZE(szError))){
				strError += _T(" - ");
				strError += szError;
			}
			LogError(LOG_STATUSBAR, _T("%s"), strError);
		}
		return false;
	}
	try {
		//setvbuf(file.m_pStream, NULL, _IOFBF, 16384);
		uint32 nExistingSize = (UINT)file.GetLength();
		uint16 nHashCount;
		while (file.GetPosition() < nExistingSize){
			liKnown2Hashs.AddTail(CAICHHash(&file));
			nHashCount = file.ReadUInt16();
			if (file.GetPosition() + nHashCount*CAICHHash::GetHashSize() > nExistingSize){
				AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName());
			}
			// skip the rest of this hashset
			file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current);
			nLastVerifiedPos = (UINT)file.GetPosition();
		}
	}
	catch(CFileException* error){
		if (error->m_cause == CFileException::endOfFile){
			LogError(LOG_STATUSBAR,GetResString(IDS_ERR_SERVERMET_BAD));
			// truncate the file to the size to the last verified valid pos
			try{
				file.SetLength(nLastVerifiedPos);
			}
			catch(CFileException* error2){
				error2->Delete();
			}
		}
		else{
			TCHAR buffer[MAX_CFEXP_ERRORMSG];
			error->GetErrorMessage(buffer, ARRSIZE(buffer));
			LogError(LOG_STATUSBAR,GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer);
		}
		error->Delete();
		return false;
	}
	
	// now we check that all files which are in the sharedfilelist have a corresponding hash in out list
	// those how don'T are added to the hashinglist
	CList<CAICHHash> liUsedHashs;	
	CSingleLock sharelock(&theApp.sharedfiles->m_mutWriteList);
	sharelock.Lock();

	for (uint32 i = 0; i < theApp.sharedfiles->GetCount(); i++){
		CKnownFile* pCurFile = theApp.sharedfiles->GetFileByIndex(i);
		if (pCurFile != NULL && !pCurFile->IsPartFile() ){
			if (theApp.emuledlg==NULL || !theApp.emuledlg->IsRunning()) // in case of shutdown while still hashing
				return 0;
			if (pCurFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE){
				bool bFound = false;
				for (POSITION pos = liKnown2Hashs.GetHeadPosition();pos != 0;)
				{
					CAICHHash current_hash = liKnown2Hashs.GetNext(pos);
					if (current_hash == pCurFile->GetAICHHashset()->GetMasterHash()){
						bFound = true;
						liUsedHashs.AddTail(current_hash);
						//theApp.QueueDebugLogLine(false, _T("%s - %s"), current_hash.GetString(), pCurFile->GetFileName());
#ifdef _DEBUG
						// in debugmode we load and verify all hashsets
						ASSERT( pCurFile->GetAICHHashset()->LoadHashSet() );
//			 			pCurFile->GetAICHHashset()->DbgTest();
						pCurFile->GetAICHHashset()->FreeHashSet();
#endif
						break;
					}
				}
				if (bFound) // hashset is available, everything fine with this file
					continue;
			}
			pCurFile->GetAICHHashset()->SetStatus(AICH_ERROR);
			m_liToHash.AddTail(pCurFile);
		}
	}
	sharelock.Unlock();

	// removed all unused AICH hashsets from known2.met
	if (!thePrefs.IsRememberingDownloadedFiles() && liUsedHashs.GetCount() != liKnown2Hashs.GetCount()){
		file.SeekToBegin();
		try {
			uint32 nExistingSize = (UINT)file.GetLength();
			uint16 nHashCount;
			ULONGLONG posWritePos = 0;
			ULONGLONG posReadPos = 0;
			uint32 nPurgeCount = 0;
			while (file.GetPosition() < nExistingSize){
				CAICHHash aichHash(&file);
				nHashCount = file.ReadUInt16();
				if (file.GetPosition() + nHashCount*CAICHHash::GetHashSize() > nExistingSize){
					AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName());
				}
				if (liUsedHashs.Find(aichHash) == NULL){
					// unused hashset skip the rest of this hashset
					file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current);
					nPurgeCount++;
				}
				else if(nPurgeCount == 0){
					// used Hashset, but it does not need to be moved as nothing changed yet
					file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current);
					posWritePos = file.GetPosition();
				}
				else{
					// used Hashset, move position in file
					BYTE* buffer = new BYTE[nHashCount*CAICHHash::GetHashSize()];
					file.Read(buffer, nHashCount*CAICHHash::GetHashSize());
					posReadPos = file.GetPosition();
					file.Seek(posWritePos, CFile::begin);
					file.Write(aichHash.GetRawHash(), CAICHHash::GetHashSize());
					file.WriteUInt16(nHashCount);
					file.Write(buffer, nHashCount*CAICHHash::GetHashSize());
					delete[] buffer;
					posWritePos = file.GetPosition();
					file.Seek(posReadPos, CFile::begin); 
				}
			}
			posReadPos = file.GetPosition();
			file.SetLength(posWritePos);
			theApp.QueueDebugLogLine(false, _T("Cleaned up known2.met, removed %u hashsets (%s)"), nPurgeCount, CastItoXBytes(posReadPos-posWritePos)); 

			file.Flush();
			file.Close();
		}
		catch(CFileException* error){
			if (error->m_cause == CFileException::endOfFile){
				// we just parsed this files some ms ago, should never happen here
				ASSERT( false );
			}
			else{
				TCHAR buffer[MAX_CFEXP_ERRORMSG];
				error->GetErrorMessage(buffer, ARRSIZE(buffer));
				LogError(LOG_STATUSBAR,GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer);
			}
			error->Delete();
			return false;
		}
	}
	lockKnown2Met.Unlock();
	// warn the user if he just upgraded
	if (thePrefs.IsFirstStart() && !m_liToHash.IsEmpty()){
		LogWarning(GetResString(IDS_AICH_WARNUSER));
	}	
	if (!m_liToHash.IsEmpty()){
		theApp.QueueLogLine(true, GetResString(IDS_AICH_SYNCTOTAL), m_liToHash.GetCount() );
		theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(m_liToHash.GetCount());
		// let first all normal hashing be done before starting out synchashing
		CSingleLock sLock1(&theApp.hashing_mut); // only one filehash at a time
		while (theApp.sharedfiles->GetHashingCount() != 0){
			Sleep(100);
		}
		sLock1.Lock();
		uint32 cDone = 0;
		for (POSITION pos = m_liToHash.GetHeadPosition();pos != 0; cDone++)
		{
			if (theApp.emuledlg==NULL || !theApp.emuledlg->IsRunning()){ // in case of shutdown while still hashing
				return 0;
			}
			theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(m_liToHash.GetCount()-cDone);
			if (theApp.emuledlg->sharedfileswnd->sharedfilesctrl.m_hWnd != NULL)
				theApp.emuledlg->sharedfileswnd->sharedfilesctrl.ShowFilesCount();
			CKnownFile* pCurFile = m_liToHash.GetNext(pos);
			// just to be sure that the file hasnt been deleted lately
			if (!(theApp.knownfiles->IsKnownFile(pCurFile) && theApp.sharedfiles->GetFileByID(pCurFile->GetFileHash())) )
				continue;
			theApp.QueueLogLine(false, GetResString(IDS_AICH_CALCFILE), pCurFile->GetFileName());
			if(!pCurFile->CreateAICHHashSetOnly())
				theApp.QueueDebugLogLine(false, _T("Failed to create AICH Hashset while sync. for file %s"), pCurFile->GetFileName());
		}

		theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(0);
		if (theApp.emuledlg->sharedfileswnd->sharedfilesctrl.m_hWnd != NULL)
			theApp.emuledlg->sharedfileswnd->sharedfilesctrl.ShowFilesCount();
		sLock1.Unlock();
	}

	theApp.QueueDebugLogLine(false, _T("AICHSyncThread finished"));
	return 0;
}
bool CClientUDPSocket::ProcessPacket(const BYTE* packet, uint16 size, uint8 opcode, uint32 ip, uint16 port)
{
	switch(opcode)
	{
		case OP_REASKCALLBACKUDP:
		{
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_ReaskCallbackUDP", NULL, NULL, ip);
			theStats.AddDownDataOverheadOther(size);
			CUpDownClient* buddy = theApp.clientlist->GetBuddy();
			if( buddy )
			{
				if( size < 17 || buddy->socket == NULL )
					break;
				if (!md4cmp(packet, buddy->GetBuddyID()))
				{
					PokeUInt32(const_cast<BYTE*>(packet)+10, ip);
					PokeUInt16(const_cast<BYTE*>(packet)+14, port);
					Packet* response = new Packet(OP_EMULEPROT);
					response->opcode = OP_REASKCALLBACKTCP;
					response->pBuffer = new char[size];
					memcpy(response->pBuffer, packet+10, size-10);
					response->size = size-10;
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugSend("OP__ReaskCallbackTCP", buddy);
					theStats.AddUpDataOverheadFileRequest(response->size);
					buddy->socket->SendPacket(response);
				}
			}
			break;
		}
		case OP_REASKFILEPING:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CSafeMemFile data_in(packet, size);
			uchar reqfilehash[16];
			data_in.ReadHash16(reqfilehash);
			CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(reqfilehash);
			if (!reqfile)
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0) {
					DebugRecv("OP_ReaskFilePing", NULL, reqfilehash, ip);
					DebugSend("OP__FileNotFound", NULL);
				}

				Packet* response = new Packet(OP_FILENOTFOUND,0,OP_EMULEPROT);
				theStats.AddUpDataOverheadFileRequest(response->size);
				SendPacket(response, ip, port);
				break;
			}
			CUpDownClient* sender = theApp.uploadqueue->GetWaitingClientByIP_UDP(ip, port);
			if (sender)
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugRecv("OP_ReaskFilePing", sender, reqfilehash);

				//Make sure we are still thinking about the same file
				if (md4cmp(reqfilehash, sender->GetUploadFileID()) == 0)
				{
					sender->AddAskedCount();
					sender->SetLastUpRequest();
					//I messed up when I first added extended info to UDP
					//I should have originally used the entire ProcessExtenedInfo the first time.
					//So now I am forced to check UDPVersion to see if we are sending all the extended info.
					//For now on, we should not have to change anything here if we change
					//anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
					//Update extended info. 
					if (sender->GetUDPVersion() > 3)
					{
						sender->ProcessExtendedInfo(&data_in, reqfile);
					}
					//Update our complete source counts.
					else if (sender->GetUDPVersion() > 2)
					{
						uint16 nCompleteCountLast= sender->GetUpCompleteSourcesCount();
						uint16 nCompleteCountNew = data_in.ReadUInt16();
						sender->SetUpCompleteSourcesCount(nCompleteCountNew);
						if (nCompleteCountLast != nCompleteCountNew)
						{
							reqfile->UpdatePartsInfo();
						}
					}
					CSafeMemFile data_out(128);
					if(sender->GetUDPVersion() > 3)
					{
						if (reqfile->IsPartFile())
							((CPartFile*)reqfile)->WritePartStatus(&data_out);
						else
							data_out.WriteUInt16(0);
					}
					data_out.WriteUInt16(theApp.uploadqueue->GetWaitingPosition(sender));
					if (thePrefs.GetDebugClientUDPLevel() > 0)
						DebugSend("OP__ReaskAck", sender);
					Packet* response = new Packet(&data_out, OP_EMULEPROT);
					response->opcode = OP_REASKACK;
					theStats.AddUpDataOverheadFileRequest(response->size);
					theApp.clientudp->SendPacket(response, ip, port);
				}
				else
				{
					DebugLogError(_T("Client UDP socket; ReaskFilePing; reqfile does not match"));
					TRACE(_T("reqfile:         %s\n"), DbgGetFileInfo(reqfile->GetFileHash()));
					TRACE(_T("sender->GetRequestFile(): %s\n"), sender->GetRequestFile() ? DbgGetFileInfo(sender->GetRequestFile()->GetFileHash()) : _T("(null)"));
				}
			}
			else
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugRecv("OP_ReaskFilePing", NULL, reqfilehash, ip);

				if (((uint32)theApp.uploadqueue->GetWaitingUserCount() + 50) > thePrefs.GetQueueSize())
				{
					if (thePrefs.GetDebugClientUDPLevel() > 0)
						DebugSend("OP__QueueFull", NULL);
					Packet* response = new Packet(OP_QUEUEFULL,0,OP_EMULEPROT);
					theStats.AddUpDataOverheadFileRequest(response->size);
					SendPacket(response, ip, port);
				}
			}
			break;
		}
		case OP_QUEUEFULL:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_QueueFull", sender, NULL, ip);
			if (sender){
				sender->SetRemoteQueueFull(true);
				sender->UDPReaskACK(0);
			}
			break;
		}
		case OP_REASKACK:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_ReaskAck", sender, NULL, ip);
			if (sender){
				CSafeMemFile data_in(packet, size);
				if ( sender->GetUDPVersion() > 3 )
				{
					sender->ProcessFileStatus(true, &data_in, sender->GetRequestFile());
				}
				uint16 nRank = data_in.ReadUInt16();
				sender->SetRemoteQueueFull(false);
				sender->UDPReaskACK(nRank);
				sender->AddAskedCountDown();
			}
			break;
		}
		case OP_FILENOTFOUND:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_FileNotFound", sender, NULL, ip);
			if (sender){
				sender->UDPReaskFNF(); // may delete 'sender'!
				sender = NULL;
			}
			break;
		}
		case OP_PORTTEST:
		{
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_PortTest", NULL, NULL, ip);
			theStats.AddDownDataOverheadOther(size);
			if (size == 1){
				if (packet[0] == 0x12){
					bool ret = theApp.listensocket->SendPortTestReply('1', true);
					AddDebugLogLine(true, _T("UDP Portcheck packet arrived - ACK sent back (status=%i)"), ret);
				}
			}
			break;
		}
		default:
			theStats.AddDownDataOverheadOther(size);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
			{
				CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port);
				Debug(_T("Unknown client UDP packet: host=%s:%u (%s) opcode=0x%02x  size=%u\n"), ipstr(ip), port, sender ? sender->DbgGetClientInfo() : _T(""), opcode, size);
			}
			return false;
	}
	return true;
}
Beispiel #11
0
int CAICHSyncThread::Run()
{
	//MORPH START SLUGFILLER: SafeHash
	CReadWriteLock lock(&theApp.m_threadlock);
	if (!lock.ReadLock(0))
		return 0;
	// MORPH END SLUGFILLER: SafeHash
	if ( !theApp.emuledlg->IsRunning() )
		return 0;
	// we need to keep a lock on this file while the thread is running
	CSingleLock lockKnown2Met(&CAICHRecoveryHashSet::m_mutKnown2File);
	lockKnown2Met.Lock();
	
	CSafeFile file;
	bool bJustCreated = ConvertToKnown2ToKnown264(&file);
	
	// we collect all masterhashs which we find in the known2.met and store them in a list
	CList<CAICHHash> liKnown2Hashs;
	CString fullpath = thePrefs.GetMuleDirectory(EMULE_CONFIGDIR);
	fullpath.Append(KNOWN2_MET_FILENAME);
	
	CFileException fexp;
	uint32 nLastVerifiedPos = 0;

	if (!bJustCreated && !file.Open(fullpath,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyNone, &fexp)){
		if (fexp.m_cause != CFileException::fileNotFound){
			CString strError(_T("Failed to load ") KNOWN2_MET_FILENAME _T(" file"));
			TCHAR szError[MAX_CFEXP_ERRORMSG];
			if (fexp.GetErrorMessage(szError, ARRSIZE(szError))){
				strError += _T(" - ");
				strError += szError;
			}
			LogError(LOG_STATUSBAR, _T("%s"), strError);
		}
		return false;
	}
	try {
		if (file.GetLength() >= 1){
			uint8 header = file.ReadUInt8();
			if (header != KNOWN2_MET_VERSION){
				AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName());
			}
			//setvbuf(file.m_pStream, NULL, _IOFBF, 16384);
			uint32 nExistingSize = (UINT)file.GetLength();
			uint32 nHashCount;
			while (file.GetPosition() < nExistingSize){
				liKnown2Hashs.AddTail(CAICHHash(&file));
				nHashCount = file.ReadUInt32();
				if (file.GetPosition() + nHashCount*CAICHHash::GetHashSize() > nExistingSize){
					AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName());
				}
				// skip the rest of this hashset
				file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current);
				nLastVerifiedPos = (UINT)file.GetPosition();
			}
		}
		else
			file.WriteUInt8(KNOWN2_MET_VERSION);
	}
	catch(CFileException* error){
		if (error->m_cause == CFileException::endOfFile){
			LogError(LOG_STATUSBAR,GetResString(IDS_ERR_MET_BAD), KNOWN2_MET_FILENAME);
			// truncate the file to the size to the last verified valid pos
			try{
				file.SetLength(nLastVerifiedPos);
				if (file.GetLength() == 0){
					file.SeekToBegin();
					file.WriteUInt8(KNOWN2_MET_VERSION);
				}
			}
			catch(CFileException* error2){
				error2->Delete();
			}
		}
		else{
			TCHAR buffer[MAX_CFEXP_ERRORMSG];
			error->GetErrorMessage(buffer, ARRSIZE(buffer));
			LogError(LOG_STATUSBAR,GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer);
		}
		error->Delete();
		return false;
	}
	
	// now we check that all files which are in the sharedfilelist have a corresponding hash in out list
	// those who don'T are added to the hashinglist
	CList<CAICHHash> liUsedHashs;	
	CSingleLock sharelock(&theApp.sharedfiles->m_mutWriteList);
	sharelock.Lock();

	bool bDbgMsgCreatingPartHashs = true;
	for (int i = 0; i < theApp.sharedfiles->GetCount(); i++){
		CKnownFile* pCurFile = theApp.sharedfiles->GetFileByIndex(i);
		if (pCurFile != NULL && !pCurFile->IsPartFile() )
		{
			if (theApp.emuledlg==NULL || !theApp.emuledlg->IsRunning()) // in case of shutdown while still hashing
				return 0;
			if (pCurFile->GetFileIdentifier().HasAICHHash()){
				bool bFound = false;
				for (POSITION pos = liKnown2Hashs.GetHeadPosition();pos != 0;)
				{
					CAICHHash current_hash = liKnown2Hashs.GetNext(pos);
					if (current_hash == pCurFile->GetFileIdentifier().GetAICHHash()){
						bFound = true;
						liUsedHashs.AddTail(current_hash);
						pCurFile->SetAICHRecoverHashSetAvailable(true);
						// Has the file the proper AICH Parthashset? If not probably upgrading, create it
						if (!pCurFile->GetFileIdentifier().HasExpectedAICHHashCount())
						{
							if (bDbgMsgCreatingPartHashs)
							{
								bDbgMsgCreatingPartHashs = false;
								DebugLogWarning(_T("Missing AICH Part Hashsets for known files - maybe upgrading from earlier version. Creating them out of full AICH Recovery Hashsets, shouldn't take too long"));
							}
							CAICHRecoveryHashSet tempHashSet(pCurFile, pCurFile->GetFileSize());
							tempHashSet.SetMasterHash(pCurFile->GetFileIdentifier().GetAICHHash(), AICH_HASHSETCOMPLETE);
							if (!tempHashSet.LoadHashSet())
							{
								ASSERT( false );
								DebugLogError(_T("Failed to load full AICH Recovery Hashset - known2.met might be corrupt. Unable to create AICH Part Hashset - %s"), pCurFile->GetFileName());
							}
							else
							{
								if (!pCurFile->GetFileIdentifier().SetAICHHashSet(tempHashSet))
								{
									DebugLogError(_T("Failed to create AICH Part Hashset out of full AICH Recovery Hashset - %s"), pCurFile->GetFileName());
									ASSERT( false );
								}
								ASSERT(pCurFile->GetFileIdentifier().HasExpectedAICHHashCount());
							}
						}
						//theApp.QueueDebugLogLine(false, _T("%s - %s"), current_hash.GetString(), pCurFile->GetFileName());
						/*#ifdef _DEBUG
						// in debugmode we load and verify all hashsets
						CAICHRecoveryHashSet* pTempHashSet = new CAICHRecoveryHashSet(pCurFile);
						pTempHashSet->SetFileSize(pCurFile->GetFileSize());
						pTempHashSet->SetMasterHash(pCurFile->GetFileIdentifier().GetAICHHash(), AICH_HASHSETCOMPLETE)
						ASSERT( pTempHashSet->LoadHashSet() );
						delete pTempHashSet;
#endif*/
						break;
					}
				}
				if (bFound) // hashset is available, everything fine with this file
					continue;
			}
			pCurFile->SetAICHRecoverHashSetAvailable(false);
			m_liToHash.AddTail(pCurFile);
		}
	}
	sharelock.Unlock();

	// removed all unused AICH hashsets from known2.met
	if (liUsedHashs.GetCount() != liKnown2Hashs.GetCount() && 
		// EastShare START - Added by TAHO, .met file control
		/*
		(!thePrefs.IsRememberingDownloadedFiles() || thePrefs.DoPartiallyPurgeOldKnownFiles()))
		*/
			(!thePrefs.IsRememberingDownloadedFiles() ||
			  thePrefs.DoPartiallyPurgeOldKnownFiles() || 
			  thePrefs.DoCompletlyPurgeOldKnownFiles() ||
			  thePrefs.DoRemoveAichImmediatly()
			)
		)
		// EastShare END   - Added by TAHO, .met file control
	{
		file.SeekToBegin();
		try {
			uint8 header = file.ReadUInt8();
			if (header != KNOWN2_MET_VERSION){
				AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName());
			}

			uint32 nExistingSize = (UINT)file.GetLength();
			uint32 nHashCount;
			ULONGLONG posWritePos = file.GetPosition();
			ULONGLONG posReadPos = file.GetPosition();
			uint32 nPurgeCount = 0;
			uint32 nPurgeBecauseOld = 0;
			while (file.GetPosition() < nExistingSize){
				CAICHHash aichHash(&file);
				nHashCount = file.ReadUInt32();
				if (file.GetPosition() + nHashCount*CAICHHash::GetHashSize() > nExistingSize){
					AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName());
				}
				if (!thePrefs.IsRememberingDownloadedFiles() && liUsedHashs.Find(aichHash) == NULL)
				{
					// unused hashset skip the rest of this hashset
					file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current);
					nPurgeCount++;
				}
				else if (thePrefs.IsRememberingDownloadedFiles() && theApp.knownfiles->ShouldPurgeAICHHashset(aichHash))
				{
					// EastShare START - Added by TAHO, .met file control
					/*
					ASSERT( thePrefs.DoPartiallyPurgeOldKnownFiles() );
					*/
					ASSERT( thePrefs.DoPartiallyPurgeOldKnownFiles() || thePrefs.DoRemoveAichImmediatly());
					// EastShare END   - Added by TAHO, .met file control
					// also unused (purged) hashset skip the rest of this hashset
					file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current);
					nPurgeCount++;
					nPurgeBecauseOld++;
				}
				else if(nPurgeCount == 0){
					// used Hashset, but it does not need to be moved as nothing changed yet
					file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current);
					posWritePos = file.GetPosition();
					CAICHRecoveryHashSet::AddStoredAICHHash(aichHash);
				}
				else{
					// used Hashset, move position in file
					BYTE* buffer = new BYTE[nHashCount*CAICHHash::GetHashSize()];
					file.Read(buffer, nHashCount*CAICHHash::GetHashSize());
					posReadPos = file.GetPosition();
					file.Seek(posWritePos, CFile::begin);
					file.Write(aichHash.GetRawHash(), CAICHHash::GetHashSize());
					file.WriteUInt32(nHashCount);
					file.Write(buffer, nHashCount*CAICHHash::GetHashSize());
					delete[] buffer;
					posWritePos = file.GetPosition();
					file.Seek(posReadPos, CFile::begin);
					CAICHRecoveryHashSet::AddStoredAICHHash(aichHash);
				}
			}
			posReadPos = file.GetPosition();
			file.SetLength(posWritePos);
			theApp.QueueDebugLogLine(false, _T("Cleaned up known2.met, removed %u hashsets and purged %u hashsets of old known files (%s)")
				, nPurgeCount - nPurgeBecauseOld, nPurgeBecauseOld, CastItoXBytes(posReadPos-posWritePos)); 

			file.Flush();
			file.Close();
		}
		catch(CFileException* error){
			if (error->m_cause == CFileException::endOfFile){
				// we just parsed this files some ms ago, should never happen here
				ASSERT( false );
			}
			else{
				TCHAR buffer[MAX_CFEXP_ERRORMSG];
				error->GetErrorMessage(buffer, ARRSIZE(buffer));
				LogError(LOG_STATUSBAR,GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer);
			}
			error->Delete();
			return false;
		}
	}
	else
	{
		// remember (/index) all hashs which are stored in the file for faster checking lateron
		for (POSITION pos = liKnown2Hashs.GetHeadPosition();pos != 0;)
		{
			CAICHRecoveryHashSet::AddStoredAICHHash(liKnown2Hashs.GetNext(pos));
		}
	}
	lockKnown2Met.Unlock();
	// warn the user if he just upgraded
	if (thePrefs.IsFirstStart() && !m_liToHash.IsEmpty() && !bJustCreated){
		LogWarning(GetResString(IDS_AICH_WARNUSER));
	}	
	if (!m_liToHash.IsEmpty()){
		theApp.QueueLogLine(true, GetResString(IDS_AICH_SYNCTOTAL), m_liToHash.GetCount() );
		theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(m_liToHash.GetCount());
		// let first all normal hashing be done before starting out synchashing
		CSingleLock sLock1(&theApp.hashing_mut); // only one filehash at a time
		while (theApp.sharedfiles->GetHashingCount() != 0){
			Sleep(100);
			if (!CemuleDlg::IsRunning())
				return 0;
		}
		sLock1.Lock();
		uint32 cDone = 0;
		for (POSITION pos = m_liToHash.GetHeadPosition();pos != 0; cDone++)
		{
			if (!CemuleDlg::IsRunning()){ // in case of shutdown while still hashing
				return 0;
			}
			theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(m_liToHash.GetCount()-cDone);
			if (theApp.emuledlg->sharedfileswnd->sharedfilesctrl.m_hWnd != NULL)
				theApp.emuledlg->sharedfileswnd->sharedfilesctrl.ShowFilesCount();
			CKnownFile* pCurFile = m_liToHash.GetNext(pos);
			// just to be sure that the file hasnt been deleted lately
			if (!(theApp.knownfiles->IsKnownFile(pCurFile) && theApp.sharedfiles->GetFileByID(pCurFile->GetFileHash())) )
				continue;
			theApp.QueueLogLine(false, GetResString(IDS_AICH_CALCFILE), pCurFile->GetFileName());
			if(!pCurFile->CreateAICHHashSetOnly())
				theApp.QueueDebugLogLine(false, _T("Failed to create AICH Hashset while sync. for file %s"), pCurFile->GetFileName());
		}

		theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(0);
		if (theApp.emuledlg->sharedfileswnd->sharedfilesctrl.m_hWnd != NULL)
			theApp.emuledlg->sharedfileswnd->sharedfilesctrl.ShowFilesCount();
		sLock1.Unlock();
	}

	theApp.QueueDebugLogLine(false, _T("AICHSyncThread finished"));
	return 0;
}