Ejemplo n.º 1
0
void CDownloadTask::RunMergeFile(CDownload* pDownload, LPCTSTR szFilename, BOOL bMergeValidation, const Fragments::List& oMissedGaps, float fProgress)
{
//	HANDLE hSource = CreateFile( szFilename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );

	QWORD nSourceSize = 0;		// qwSourceLength
	QWORD nSourceOffset = 0;	// qwSourceOffset

	CAtlFile oSource;
	oSource.Create( szFilename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, OPEN_EXISTING );
	VERIFY_FILE_ACCESS( oSource, szFilename )
	if ( ! oSource )
	{
		// Source file open error
		theApp.Message( MSG_ERROR, IDS_DOWNLOAD_FILE_OPEN_ERROR, szFilename );
		return;
	}

	oSource.GetSize( nSourceSize );
	if ( ! nSourceSize )
		return;		// Empty source file

	CSingleLock pLock( &Transfers.m_pSection, TRUE );

	if ( ! Downloads.Check( pDownload ) ||
		  pDownload->IsCompleted() ||
		  pDownload->IsMoving() )
		return;		// Moot download almost completed

	if ( m_bMergeValidation &&
		! pDownload->IsTorrent() &&
		 pDownload->NeedTigerTree() &&
		 pDownload->NeedHashset() )
	{
	//	pLock.Unlock();
	//	MsgBox( IDS_DOWNLOAD_EDIT_COMPLETE_NOHASH, MB_ICONEXCLAMATION );
		DEBUG_ONLY( theApp.Message( MSG_DEBUG, IDS_DOWNLOAD_EDIT_COMPLETE_NOHASH ) );
		return;		// No hashsets
	}

	if ( ! pDownload->PrepareFile() )
		return;		// Destination file open error

	Fragments::List oList( pDownload->GetEmptyFragmentList() );
	if ( ! oMissedGaps.empty() )
	{
		Fragments::List::const_iterator pItr = oMissedGaps.begin();
		const Fragments::List::const_iterator pEnd = oMissedGaps.end();
		for ( ; pItr != pEnd ; ++pItr )
			oList.erase( *pItr );
	}

	if ( ! oList.size() )
		return;		// No available fragments

	// Determine offset if needed
	if ( pDownload->IsMultiFileTorrent() )
	{
		QWORD nOffset = 0;		// qwOffset
		BOOL bFound = FALSE;
		CBTInfo::CBTFile* pFile;
		CString strTargetName;
		const CString strSourceName = PathFindFileName( szFilename );

		if ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 )	// Forced selection dialog
		{
			int nIndex = pDownload->SelectFile( &pLock );
			if ( nIndex == 0 )
			{
				bFound = TRUE;
			}
			else if ( nIndex > 0 )
			{
				CBTInfo::CBTFile* pSelectFile = pDownload->m_pTorrent.m_pFiles.GetAt( pDownload->m_pTorrent.m_pFiles.FindIndex( nIndex ) );
				for ( POSITION pos = pDownload->m_pTorrent.m_pFiles.GetHeadPosition() ; pos ; )
				{
					pFile = pDownload->m_pTorrent.m_pFiles.GetNext( pos );
					if ( pFile->m_sPath == pSelectFile->m_sPath )
					{
						DEBUG_ONLY( theApp.Message( MSG_DEBUG, _T("Merge Selected File: ") + pFile->m_sPath ) );
						nSourceOffset = nOffset;
						bFound = TRUE;	// Avoid checks below
						break;
					}

					nOffset += pFile->m_nSize;
				}
			}
		}

		if ( ! bFound )		// No forced match, try filename
		{
			for ( POSITION pos = pDownload->m_pTorrent.m_pFiles.GetHeadPosition() ; pos ; )
			{
				pFile = pDownload->m_pTorrent.m_pFiles.GetNext( pos );
				strTargetName = PathFindFileName( pFile->m_sPath );

				if ( strTargetName.CompareNoCase( strSourceName ) == 0 )
				{
					DEBUG_ONLY( theApp.Message( MSG_DEBUG, _T("Merge Filename: ") + pFile->m_sPath ) );
					nSourceOffset = nOffset;
					bFound = TRUE;	// Avoid fallback check below
					break;
				}

				nOffset += pFile->m_nSize;
			}
		}

		if ( ! bFound )		// No filename match, try exact size
		{
			nOffset = 0;
		//	const CString strExt = PathFindExtension( strSourceName );
			for ( POSITION pos = pDownload->m_pTorrent.m_pFiles.GetHeadPosition() ; pos ; )
			{
				pFile = pDownload->m_pTorrent.m_pFiles.GetNext( pos );

				if ( pFile->m_nSize == nSourceSize )	// && strExt == PathFindExtension( pFile->m_sPath )
				{
					DEBUG_ONLY( theApp.Message( MSG_DEBUG, _T("Merge Filesize Fallback") ) );
					nSourceOffset = nOffset;
				//	bFound = TRUE;
					break;
				}

				nOffset += pFile->m_nSize;
			}
		}
	}

	pLock.Unlock();

	const float fIncrement = fProgress / oList.size();

	const DWORD nBufferLength = 256 * 1024;		// Was 65536?

	// Read missing file fragments from selected file
	auto_array< BYTE > Buf( new BYTE [nBufferLength] );
	Fragments::List::const_iterator pItr = oList.begin();
	const Fragments::List::const_iterator pEnd = oList.end();
	for ( ; ! m_pEvent && pItr != pEnd ; ++pItr )
	{
		m_fProgress += fIncrement;		// Update tooltip

		QWORD qwLength = pItr->end() - pItr->begin();
		QWORD qwOffset = pItr->begin();

		// Check for overlapped fragments
		if ( qwOffset + qwLength <= nSourceOffset ||
			 nSourceOffset + nSourceSize <= qwOffset )
			 continue;	 // No overlaps

		// Calculate overlapped range end offset
		QWORD qwEnd = min( qwOffset + qwLength, nSourceOffset + nSourceSize );
		// Calculate overlapped range start offset
		qwOffset = max( qwOffset, nSourceOffset );
		// Calculate overlapped range length
		qwLength = qwEnd - qwOffset;
		// Calculate file offset if any
		QWORD qwFileOffset = ( qwOffset > nSourceOffset ) ? qwOffset - nSourceOffset : 0;
		if ( FAILED( oSource.Seek( qwFileOffset, FILE_BEGIN ) ) )
			continue;

		DWORD dwToRead;
		while ( ( dwToRead = (DWORD)min( qwLength, (QWORD)nBufferLength ) ) != 0 && ! m_pEvent )
		{
			DWORD dwReaded = 0;
			if ( SUCCEEDED( oSource.Read( Buf.get(), dwToRead, dwReaded ) ) && dwReaded )
			{
				pLock.Lock();

				if ( ! Downloads.Check( pDownload ) || pDownload->IsCompleted() || pDownload->IsMoving() )
					return;

				pDownload->SubmitData( qwOffset, Buf.get(), (QWORD)dwReaded );
				pLock.Unlock();
				qwOffset += (QWORD)dwReaded;
				qwLength -= (QWORD)dwReaded;
			}
			else
			{
				// File error or end of file. Non-Fatal
				break;
			}
		}

		pLock.Lock();

		if ( ! Downloads.Check( pDownload ) || pDownload->IsCompleted() || pDownload->IsMoving() )
			return;

		if ( bMergeValidation )
			pDownload->RunValidation();

		pDownload->SetModified();

		pLock.Unlock();
	}

//	m_bSuccess = true;
}
Ejemplo n.º 2
0
blockPair CDownloadTransfer::SelectBlock(const Fragments::List& oPossible, const std::vector< bool >& pAvailable, bool bEndGame) const
{
	ASSUME_LOCK( Transfers.m_pSection );

	if ( oPossible.empty() )
		return std::make_pair( 0ull, 0ull );

	Fragments::List::const_iterator pItr = oPossible.begin();
	const Fragments::List::const_iterator pEnd = oPossible.end();

	if ( bEndGame )
	{
		std::vector< blockPair > oPartials;
		for ( ; pItr != pEnd && oPartials.size() < oPartials.max_size(); ++pItr )
		{
			oPartials.push_back(
				std::make_pair( pItr->begin(), pItr->end() - pItr->begin() ) );
		}

		return oPartials[ GetRandomNum< size_t >( 0u, oPartials.size() - 1u ) ];
	}

	if ( pItr->begin() < Settings.Downloads.ChunkStrap )
	{
		return std::make_pair( pItr->begin(),
			min( pItr->end() - pItr->begin(), (QWORD)Settings.Downloads.ChunkStrap ) );
	}

	DWORD nBlockSize = m_pDownload->GetVerifyLength( m_nProtocol );
	if ( ! nBlockSize )
		return std::make_pair( pItr->begin(), pItr->end() - pItr->begin() );

	std::vector< QWORD > oBlocks;
	QWORD nRangeBlock = 0ull;
	QWORD nRange[3] = { 0ull, 0ull, 0ull };
	QWORD nBestRange[3] = { 0ull, 0ull, 0ull };

	for ( ; pItr != pEnd; ++pItr )
	{
		QWORD nPart[2] = { pItr->begin(), 0ull };
		QWORD nBlockBegin = nPart[0] / nBlockSize;
		const QWORD nBlockEnd = ( pItr->end() - 1ull ) / nBlockSize;

		// The start of a block is complete, but part is missing
		if ( nPart[0] % nBlockSize
			&& ( nBlockBegin >= pAvailable.size() || pAvailable[ (DWORD)nBlockBegin ] ) )
		{
			nPart[1] = min( pItr->end(), nBlockSize * ( nBlockBegin + 1ull ) );
			nPart[1] -= nPart[0];
			CheckPart( nPart, nBlockBegin, nRange, nRangeBlock, nBestRange );
		}

		// The end of a block is complete, but part is missing
		if ( ( ! nPart[1] || nBlockBegin != nBlockEnd )
			&& pItr->end() % nBlockSize
			&& ( nBlockEnd >= pAvailable.size() || pAvailable[ (DWORD)nBlockEnd ] ) )
		{
			nPart[0] = nBlockEnd * nBlockSize;
			nPart[1] = pItr->end() - nPart[0];
			CheckPart( nPart, nBlockEnd, nRange, nRangeBlock, nBestRange );
		}

		// This fragment contains one or more aligned empty blocks
		if ( ! nRange[2] )
		{
			for ( ; ( nBlockBegin <= nBlockEnd && oBlocks.size() < oBlocks.max_size() ); ++nBlockBegin )
			{
				if ( nBlockBegin >= pAvailable.size() || pAvailable[ (DWORD)nBlockBegin ] )
					oBlocks.push_back( nBlockBegin );
			}
		}
	}

	CheckRange( nRange, nBestRange );

	if ( ! nBestRange[2] )
	{
		if ( oBlocks.empty() )
			return std::make_pair( 0ull, 0ull );

		nRange[0] = oBlocks[ GetRandomNum< size_t >( 0u, oBlocks.size() - 1u ) ];
		nRange[0] *= nBlockSize;
		return std::make_pair( nRange[0], nBlockSize );
	}

	return std::make_pair( nBestRange[0], nBestRange[1] );
}