00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "FragmentedFile.h"
00026 #include "TransferFile.h"
00027
00028 #ifdef _DEBUG
00029 #undef THIS_FILE
00030 static char THIS_FILE[]=__FILE__;
00031 #define new DEBUG_NEW
00032 #endif
00033
00034 #undef _WIN32_WINNT
00035 #define _WIN32_WINNT 0x0500
00036 #include <winioctl.h>
00037
00038
00040
00041
00042 CFragmentedFile::CFragmentedFile()
00043 : m_pFile( NULL ), m_nUnflushed( 0 ), m_oFList( 0 )
00044 { }
00045
00046 CFragmentedFile::~CFragmentedFile()
00047 {
00048 Clear();
00049 }
00050
00052
00053
00054 BOOL CFragmentedFile::Create(LPCTSTR pszFile, QWORD nLength)
00055 {
00056 if ( m_pFile != NULL || m_oFList.limit() > 0 ) return FALSE;
00057 if ( nLength == 0 ) return FALSE;
00058
00059 m_pFile = TransferFiles.Open( pszFile, TRUE, TRUE );
00060 if ( m_pFile == NULL ) return FALSE;
00061
00062 m_oFList.swap( FF::SimpleFragmentList( nLength ) );
00063
00064 m_oFList.insert( FF::SimpleFragment( 0, nLength ) );
00065
00066 if ( Settings.Downloads.SparseThreshold > 0 && theApp.m_bNT &&
00067 nLength >= Settings.Downloads.SparseThreshold * 1024 )
00068 {
00069 DWORD dwOut = 0;
00070 HANDLE hFile = m_pFile->GetHandle( TRUE );
00071
00072 if ( ! DeviceIoControl( hFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwOut, NULL ) )
00073 {
00074 DWORD nError = GetLastError();
00075 theApp.Message( MSG_ERROR, _T("Unable to set sparse file: \"%s\", Win32 error %x."), pszFile, nError );
00076 }
00077 }
00078
00079 return TRUE;
00080 }
00081
00083
00084
00085 BOOL CFragmentedFile::Open(LPCTSTR pszFile)
00086 {
00087 if ( m_pFile != NULL || m_oFList.limit() == 0 ) return FALSE;
00088
00089 m_pFile = TransferFiles.Open( pszFile, TRUE, FALSE );
00090
00091 if ( m_pFile == NULL ) return FALSE;
00092
00093 return TRUE;
00094 }
00095
00097
00098
00099 BOOL CFragmentedFile::Flush()
00100 {
00101 if ( m_nUnflushed == 0 ) return FALSE;
00102 if ( m_pFile == NULL || ! m_pFile->IsOpen() ) return FALSE;
00103 FlushFileBuffers( m_pFile->GetHandle() );
00104 m_nUnflushed = 0;
00105 return TRUE;
00106 }
00107
00109
00110
00111 void CFragmentedFile::Close()
00112 {
00113 if ( m_pFile != NULL )
00114 {
00115 m_pFile->Release( TRUE );
00116 m_pFile = NULL;
00117 m_nUnflushed = 0;
00118 }
00119 }
00120
00122
00123
00124 void CFragmentedFile::Clear()
00125 {
00126 Close();
00127
00128 m_oFList.swap( FF::SimpleFragmentList( 0 ) );
00129
00130 }
00131
00133
00134
00135 BOOL CFragmentedFile::MakeComplete()
00136 {
00137 if ( m_oFList.empty() ) return FALSE;
00138
00139 m_oFList.clear();
00140
00141 if ( m_pFile != NULL )
00142 {
00143 HANDLE hFile = m_pFile->GetHandle( TRUE );
00144
00145 if ( hFile != INVALID_HANDLE_VALUE )
00146 {
00147 DWORD nSizeHigh = (DWORD)( m_oFList.limit() >> 32 );
00148 DWORD nSizeLow = (DWORD)( m_oFList.limit() & 0xFFFFFFFF );
00149 SetFilePointer( hFile, nSizeLow, (PLONG)&nSizeHigh, FILE_BEGIN );
00150 SetEndOfFile( hFile );
00151 }
00152 }
00153
00154 return TRUE;
00155 }
00156
00158
00159
00160 void CFragmentedFile::Serialize(CArchive& ar, int nVersion)
00161 {
00162 if ( ar.IsStoring() )
00163 {
00164 SerializeOut1( ar, m_oFList );
00165 }
00166 else
00167 {
00168 ASSERT( m_oFList.limit() == 0 );
00169
00170 SerializeIn1( ar, m_oFList, nVersion );
00171 }
00172 }
00173
00175
00176
00177 BOOL CFragmentedFile::IsPositionRemaining(QWORD nOffset) const
00178 {
00179 return hasPosition( m_oFList, nOffset );
00180 }
00181
00182 BOOL CFragmentedFile::DoesRangeOverlap(QWORD nOffset, QWORD nLength) const
00183 {
00184 return overlaps( m_oFList, FF::SimpleFragment( nOffset, nOffset + nLength ) );
00185 }
00186
00187 QWORD CFragmentedFile::GetRangeOverlap(QWORD nOffset, QWORD nLength) const
00188 {
00189 return overlappingSum( m_oFList, FF::SimpleFragment( nOffset, nOffset + nLength ) );
00190 }
00191
00193
00194
00195 BOOL CFragmentedFile::WriteRange(QWORD nOffset, LPCVOID pData, QWORD nLength)
00196 {
00197 if ( m_pFile == NULL ) return FALSE;
00198 if ( nLength == 0 ) return TRUE;
00199
00200 FF::SimpleFragment oMatch( nOffset, nOffset + nLength );
00201 FF::SimpleFragmentList::ConstIteratorPair
00202 pMatches = m_oFList.overlappingRange( oMatch );
00203 if ( pMatches.first == pMatches.second ) return FALSE;
00204
00205 QWORD nResult, nProcessed = 0;
00206
00207 for ( ; pMatches.first != pMatches.second; ++pMatches.first )
00208 {
00209 QWORD nStart = std::max( pMatches.first->begin(), oMatch.begin() );
00210 nResult = std::min( pMatches.first->end(), oMatch.end() ) - nStart;
00211
00212 const char* pSource
00213 = static_cast< const char* >( pData ) + nStart - oMatch.begin();
00214
00215 if ( !m_pFile->Write( nStart, pSource, nResult, &nResult ) ) return FALSE;
00216
00217 nProcessed += nResult;
00218 }
00219
00220 m_nUnflushed += nProcessed;
00221 m_oFList.erase( oMatch );
00222 return nProcessed > 0;
00223 }
00224
00226
00227
00228 BOOL CFragmentedFile::ReadRange(QWORD nOffset, LPVOID pData, QWORD nLength)
00229 {
00230 if ( m_pFile == NULL ) return FALSE;
00231 if ( nLength == 0 ) return TRUE;
00232
00233 if ( DoesRangeOverlap( nOffset, nLength ) ) return FALSE;
00234
00235 QWORD nRead = 0;
00236 m_pFile->Read( nOffset, pData, nLength, &nRead );
00237
00238 return nRead == nLength;
00239 }
00240
00242
00243
00244 QWORD CFragmentedFile::InvalidateRange(QWORD nOffset, QWORD nLength)
00245 {
00246 return m_oFList.insert( FF::SimpleFragment( nOffset, nOffset + nLength ) );
00247 }