📄 shahashset.cpp
字号:
if (m_nDataSize <= m_nBaseSize && m_bHashValid ){
if (!bNoIdent)
fileDataOut->WriteUInt16(wHashIdent);
m_Hash.Write(fileDataOut);
//theApp.AddDebugLogLine(false,_T("%s"),m_Hash.GetString(), wHashIdent, this);
return true;
}
else{
ASSERT( false );
return false;
}
}
else if (m_pLeftTree == NULL || m_pRightTree == NULL){
ASSERT( false );
return false;
}
else{
return m_pLeftTree->WriteLowestLevelHashs(fileDataOut, wHashIdent, bNoIdent)
&& m_pRightTree->WriteLowestLevelHashs(fileDataOut, wHashIdent, bNoIdent);
}
}
// recover all low level hashs from given data. hashs are assumed to be ordered in left to right - no identifier used
bool CAICHHashTree::LoadLowestLevelHashs(CFileDataIO* fileInput){
if (m_nDataSize <= m_nBaseSize){ // sanity
// lowest level, read hash
m_Hash.Read(fileInput);
//theApp.AddDebugLogLine(false,m_Hash.GetString());
m_bHashValid = true;
return true;
}
else{
uint32 nBlocks = m_nDataSize / m_nBaseSize + ((m_nDataSize % m_nBaseSize != 0 )? 1:0);
uint32 nLeft = ( ((m_bIsLeftBranch) ? nBlocks+1:nBlocks) / 2)* m_nBaseSize;
uint32 nRight = m_nDataSize - nLeft;
if (m_pLeftTree == NULL)
m_pLeftTree = new CAICHHashTree(nLeft, true, (nLeft <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE);
else{
ASSERT( m_pLeftTree->m_nDataSize == nLeft );
}
if (m_pRightTree == NULL)
m_pRightTree = new CAICHHashTree(nRight, false, (nRight <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE);
else{
ASSERT( m_pRightTree->m_nDataSize == nRight );
}
return m_pLeftTree->LoadLowestLevelHashs(fileInput)
&& m_pRightTree->LoadLowestLevelHashs(fileInput);
}
}
// write the hash, specified by wHashIdent, with Data from fileInput.
bool CAICHHashTree::SetHash(CFileDataIO* fileInput, uint16 wHashIdent, sint8 nLevel, bool bAllowOverwrite){
if (nLevel == (-1)){
// first call, check how many level we need to go
for (uint8 i = 0; i != 16 && (wHashIdent & 0x8000) == 0; i++){
wHashIdent <<= 1;
}
if (i > 15){
theApp.QueueDebugLogLine(/*DLP_HIGH,*/ false, _T("CAICHHashTree::SetHash - found invalid HashIdent (0)"));
return false;
}
else{
nLevel = 15 - i;
}
}
if (nLevel == 0){
// this is the searched hash
if (m_bHashValid && !bAllowOverwrite){
// not allowed to overwrite this hash, however move the filepointer by reading a hash
CAICHHash(file);
return true;
}
m_Hash.Read(fileInput);
m_bHashValid = true;
return true;
}
else if (m_nDataSize <= m_nBaseSize){ // sanity
// this is already the last level, cant go deeper
ASSERT( false );
return false;
}
else{
// adjust ident to point the path to the next node
wHashIdent <<= 1;
nLevel--;
uint32 nBlocks = m_nDataSize / m_nBaseSize + ((m_nDataSize % m_nBaseSize != 0 )? 1:0);
uint32 nLeft = ( ((m_bIsLeftBranch) ? nBlocks+1:nBlocks) / 2)* m_nBaseSize;
uint32 nRight = m_nDataSize - nLeft;
if ((wHashIdent & 0x8000) > 0){
if (m_pLeftTree == NULL)
m_pLeftTree = new CAICHHashTree(nLeft, true, (nLeft <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE);
else{
ASSERT( m_pLeftTree->m_nDataSize == nLeft );
}
return m_pLeftTree->SetHash(fileInput, wHashIdent, nLevel);
}
else{
if (m_pRightTree == NULL)
m_pRightTree = new CAICHHashTree(nRight, false, (nRight <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE);
else{
ASSERT( m_pRightTree->m_nDataSize == nRight );
}
return m_pRightTree->SetHash(fileInput, wHashIdent, nLevel);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////
///CAICHUntrustedHash
bool CAICHUntrustedHash::AddSigningIP(uint32 dwIP){
dwIP &= 0x00F0FFFF; // we use only the 20 most significant bytes for unique IPs
for (int i=0; i < m_adwIpsSigning.GetCount(); i++){
if (m_adwIpsSigning[i] == dwIP)
return false;
}
m_adwIpsSigning.Add(dwIP);
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////
///CAICHHashSet
CAICHHashSet::CAICHHashSet(CKnownFile* pOwner)
: m_pHashTree(0, true, PARTSIZE)
{
m_eStatus = AICH_EMPTY;
m_pOwner = pOwner;
}
CAICHHashSet::~CAICHHashSet(void)
{
FreeHashSet();
}
bool CAICHHashSet::CreatePartRecoveryData(uint32 nPartStartPos, CFileDataIO* fileDataOut, bool bDbgDontLoad){
ASSERT( m_pOwner );
if (m_pOwner->IsPartFile() || m_eStatus != AICH_HASHSETCOMPLETE){
ASSERT( false );
return false;
}
if (m_pHashTree.m_nDataSize <= EMBLOCKSIZE){
ASSERT( false );
return false;
}
if (!bDbgDontLoad){
if (!LoadHashSet()){
theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Created RecoveryData error: failed to load hashset (file: %s)"), m_pOwner->GetFileName() );
SetStatus(AICH_ERROR);
return false;
}
}
bool bResult;
uint8 nLevel = 0;
uint32 nPartSize = min(PARTSIZE, m_pOwner->GetFileSize()-nPartStartPos);
m_pHashTree.FindHash(nPartStartPos, nPartSize,&nLevel);
uint16 nHashsToWrite = (nLevel-1) + nPartSize/EMBLOCKSIZE + ((nPartSize % EMBLOCKSIZE != 0 )? 1:0);
fileDataOut->WriteUInt16(nHashsToWrite);
uint32 nCheckFilePos = fileDataOut->GetPosition();
if (m_pHashTree.CreatePartRecoveryData(nPartStartPos, nPartSize, fileDataOut, 0)){
if (nHashsToWrite*(HASHSIZE+2) != fileDataOut->GetPosition() - nCheckFilePos){
ASSERT( false );
theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Created RecoveryData has wrong length (file: %s)"), m_pOwner->GetFileName() );
bResult = false;
SetStatus(AICH_ERROR);
}
else
bResult = true;
}
else{
theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Failed to create RecoveryData for %s"), m_pOwner->GetFileName() );
bResult = false;
SetStatus(AICH_ERROR);
}
if (!bDbgDontLoad){
FreeHashSet();
}
return bResult;
}
bool CAICHHashSet::ReadRecoveryData(uint32 nPartStartPos, CSafeMemFile* fileDataIn){
if (/*TODO !m_pOwner->IsPartFile() ||*/ !(m_eStatus == AICH_VERIFIED || m_eStatus == AICH_TRUSTED) ){
ASSERT( false );
return false;
}
// at this time we check the recoverydata for the correct ammounts of hashs only
// all hash are then taken into the tree, depending on there hashidentifier (except the masterhash)
uint8 nLevel = 0;
uint32 nPartSize = min(PARTSIZE, m_pOwner->GetFileSize()-nPartStartPos);
m_pHashTree.FindHash(nPartStartPos, nPartSize,&nLevel);
uint16 nHashsToRead = (nLevel-1) + nPartSize/EMBLOCKSIZE + ((nPartSize % EMBLOCKSIZE != 0 )? 1:0);
uint16 nHashsAvailable = fileDataIn->ReadUInt16();
if (fileDataIn->GetLength()-fileDataIn->GetPosition() < nHashsToRead*(HASHSIZE+2) || nHashsToRead != nHashsAvailable){
// this check is redunant, CSafememfile would catch such an error too
theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Failed to read RecoveryData for %s - Received datasize/amounts of hashs was invalid"), m_pOwner->GetFileName() );
return false;
}
for (uint32 i = 0; i != nHashsToRead; i++){
uint16 wHashIdent = fileDataIn->ReadUInt16();
if (wHashIdent == 1 /*never allow masterhash to be overwritten*/
|| !m_pHashTree.SetHash(fileDataIn, wHashIdent,(-1), false))
{
theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Failed to read RecoveryData for %s - Error when trying to read hash into tree"), m_pOwner->GetFileName() );
VerifyHashTree(true); // remove invalid hashs which we have already written
return false;
}
}
if (VerifyHashTree(true)){
// some final check if all hashs we wanted are there
for (uint32 nPartPos = 0; nPartPos < nPartSize; nPartPos += EMBLOCKSIZE){
CAICHHashTree* phtToCheck = m_pHashTree.FindHash(nPartStartPos+nPartPos, min(EMBLOCKSIZE, nPartSize-nPartPos));
if (phtToCheck == NULL || !phtToCheck->m_bHashValid){
theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Failed to read RecoveryData for %s - Error while verifying presence of all lowest level hashs"), m_pOwner->GetFileName() );
return false;
}
}
// all done
return true;
}
else{
theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Failed to read RecoveryData for %s - Verifying received hashtree failed"), m_pOwner->GetFileName() );
return false;
}
}
// this function is only allowed to be called right after successfully calculating the hashset (!)
// will delete the hashset, after saving to free the memory
bool CAICHHashSet::SaveHashSet(){
if (m_eStatus != AICH_HASHSETCOMPLETE){
ASSERT( false );
return false;
}
if ( !m_pHashTree.m_bHashValid || m_pHashTree.m_nDataSize != m_pOwner->GetFileSize()){
ASSERT( false );
return false;
}
CString fullpath=thePrefs.GetConfigDir();
fullpath.Append(KNOWN2_MET_FILENAME);
CSafeFile file;
CFileException fexp;
if (!file.Open(fullpath,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyWrite, &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;
}
theApp.QueueLogLine(true, _T("%s"), strError);
}
return false;
}
try {
//setvbuf(file.m_pStream, NULL, _IOFBF, 16384);
// first we check if the hashset we want to write is already stored
CAICHHash CurrentHash;
uint32 nExistingSize = file.GetLength();
uint16 nHashCount;
while (file.GetPosition() < nExistingSize){
CurrentHash.Read(&file);
if (m_pHashTree.m_Hash == CurrentHash){
// this hashset if already available, no need to save it again
return true;
}
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);
}
// write hashset
m_pHashTree.m_Hash.Write(&file);
nHashCount = (PARTSIZE/EMBLOCKSIZE + ((PARTSIZE % EMBLOCKSIZE != 0)? 1 : 0)) * (m_pHashTree.m_nDataSize/PARTSIZE);
if (m_pHashTree.m_nDataSize % PARTSIZE != 0)
nHashCount += (m_pHashTree.m_nDataSize % PARTSIZE)/EMBLOCKSIZE + (((m_pHashTree.m_nDataSize % PARTSIZE) % EMBLOCKSIZE != 0)? 1 : 0);
file.WriteUInt16(nHashCount);
if (!m_pHashTree.WriteLowestLevelHashs(&file, 0, true)){
// thats bad... really
file.SetLength(nExistingSize);
theApp.QueueDebugLogLine(true, _T("Failed to save HashSet: WriteLowestLevelHashs() failed!"));
return false;
}
if (file.GetLength() != nExistingSize + (nHashCount+1)*HASHSIZE + 2){
// thats even worse
file.SetLength(nExistingSize);
theApp.QueueDebugLogLine(true, _T("Failed to save HashSet: Calculated and real size of hashset differ!"));
return false;
}
theApp.QueueDebugLogLine(false, _T("Sucessfully saved eMuleAC Hashset, %u Hashs + 1 Masterhash written"), nHashCount);
}
catch(CFileException* error){
if (error->m_cause == CFileException::endOfFile)
theApp.QueueLogLine(true,GetResString(IDS_ERR_SERVERMET_BAD));
else{
TCHAR buffer[MAX_CFEXP_ERRORMSG];
error->GetErrorMessage(buffer, ARRSIZE(buffer));
theApp.QueueLogLine(true,GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer);
}
error->Delete();
return false;
}
FreeHashSet();
return true;
}
bool CAICHHashSet::LoadHashSet(){
if (m_eStatus != AICH_HASHSETCOMPLETE){
ASSERT( false );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -