Storage.cpp
资源名称:GGBT.rar [点击查看]
上传用户:lds876
上传日期:2013-05-25
资源大小:567k
文件大小:14k
源码类别:
P2P编程
开发平台:
Visual C++
- // StorageEx.cpp: implementation of the CStorageEx class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "testbt.h"
- #include "Storage.h"
- #include "FileBase.h"
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/locking.h>
- #include "DownloaderFeedback.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- CStorageEx::CStorageEx()
- {
- m_pMain = 0;
- m_hevDone = 0;
- m_lTotalLength = 0;
- m_lMaxFilesOpen = 0;
- m_bLockWhileReading = false;
- m_bLockFiles = false;
- }
- CStorageEx::~CStorageEx()
- {
- Close();
- }
- void CStorageEx::Close()
- {
- for (map<string, FILE*>::iterator i=m_mHandles.begin(); i != m_mHandles.end(); i++)
- {
- string strFileName = (*i).first;
- FILE* pfile = (*i).second;
- assert(pfile);
- if (m_bLockWhileReading ||
- m_mWHandles.find(strFileName) != m_mWHandles.end())
- {
- _unlock_file(strFileName, pfile);
- }
- int iRet = fclose(pfile);
- assert(!iRet);
- ferror(pfile);
- }
- m_vHandleBuffer.clear();
- m_mHandles.clear();
- m_mWHandles.clear();
- m_mSizes.clear();
- m_mTimes.clear();
- m_vRange.clear();
- }
- bool CStorageEx::Create(CDownloaderFeedback* pMain, vector<CFileInfo>& vFiles,
- HANDLE hevDone, long lMaxFilesOpen, bool bLockFiles, bool bLockWhileReading)
- {
- // assert(pMain && hevDone);
- m_pMain = pMain;
- m_hevDone = hevDone;
- m_lMaxFilesOpen = lMaxFilesOpen;
- m_bLockWhileReading = bLockWhileReading;
- m_bLockFiles = bLockFiles;
- try
- {
- BLONG lTotalLength = 0;
- long lNumFiles = 0;
- for (int i=0; i<vFiles.size(); i++)
- {
- if (IsEventSet(m_hevDone))
- return true;
- if (vFiles[i].m_lFileLength != 0)
- {
- m_vRange.push_back(CRange(lTotalLength,
- lTotalLength + vFiles[i].m_lFileLength, vFiles[i].m_strFilePath));
- lNumFiles ++;
- lTotalLength += vFiles[i].m_lFileLength;
- BLONG lsize = 0;
- if (!_access(vFiles[i].m_strFilePath.data(), 0))
- {
- lsize = GetFileSize(vFiles[i].m_strFilePath.data());
- if (lsize > vFiles[i].m_lFileLength)
- {
- lsize = vFiles[i].m_lFileLength;
- FILE* pfile = fopen(vFiles[i].m_strFilePath.data(), "rb+");
- if (!pfile)
- {
- assert(pfile);
- return false; // throw string("truncate file(") + vFiles[i].m_strFilePath + ") error";
- }
- int fh = _fileno(pfile);
- int iRet = chsize(fh, vFiles[i].m_lFileLength);
- assert(iRet == 0);
- fclose(pfile);
- }
- }
- else // not exist.
- {
- lsize = 0;
- FILE* pfile = fopen(vFiles[i].m_strFilePath.data(), "wb+");
- if (!pfile)
- {
- assert(false);
- return false; // throw string("create file(") + vFiles[i].m_strFilePath + ") error";
- }
- fclose(pfile);
- }
- m_mTops[vFiles[i].m_strFilePath] = lsize;
- m_mSizes[vFiles[i].m_strFilePath] = vFiles[i].m_lFileLength;
- m_mTimes[vFiles[i].m_strFilePath] = getfiletime(vFiles[i].m_strFilePath);
- }
- else // file length = 0.
- {
- if (!_access(vFiles[i].m_strFilePath.data(), 0))
- {
- BLONG lsize = GetFileSize(vFiles[i].m_strFilePath.data());
- if (lsize > 0)
- throw string("file exist length too large, should be zero");
- }
- else
- {
- }
- }
- } // end for
- // for (i =0; i<m_vRange.size(); i++)
- // m_vBegins.push_back(m_vRange[i].m_lbeg);
- m_lTotalLength = lTotalLength;
- m_bMaxFilesOpen = (m_lMaxFilesOpen > 0 && (lNumFiles > m_lMaxFilesOpen));
- } // end try
- catch (string e)
- {
- throw e;
- }
- return true;
- }
- bool CStorageEx::GetFilesRange(vector<long>& vRangeHoles, vector<long>& vFileOffset, long lPieceLen)
- {
- if (!lPieceLen)
- return false;
- vRangeHoles.clear();
- vFileOffset.clear();
- vRangeHoles.push_back(0);
- vFileOffset.push_back(0);
- BLONG lbeg = 0, lend = 0;
- for (int i=0; i<m_vRange.size(); i++)
- {
- lbeg = m_vRange[i].m_lbeg;
- if ((lbeg - lend) > lPieceLen)
- {
- vFileOffset.push_back(lbeg % lPieceLen);
- vRangeHoles.push_back(lbeg / lPieceLen);
- lend = lbeg;
- }
- }
- #ifdef _DEBUG
- TRACE("rn**vRangeHolesIndex : {rn");
- for (i=0; i<vRangeHoles.size();i++)
- {
- TRACE("%d, ", vRangeHoles[i]);
- }
- TRACE("}rn");
- #endif
- return true;
- }
- void CStorageEx::GetUnNeededRanges(const vector<CSize>& vUnNeededFileInxs, vector<CSizeEx>& vUnNeededRanges) const
- {
- vUnNeededRanges.clear();
- for (int i=0; i<vUnNeededFileInxs.size(); i++)
- {
- assert(vUnNeededFileInxs[i].cy > vUnNeededFileInxs[i].cx);
- assert(vUnNeededFileInxs[i].cx >= 0);
- if((vUnNeededFileInxs[i].cy - 1) >= m_vRange.size())
- {
- /*
- CSize lData[1000] = {CSize(0, 0)};
- for (int j=0; j<vUnNeededFileInxs.size(); j++)
- {
- lData[j] = vUnNeededFileInxs[j];
- }
- long lsize = vUnNeededFileInxs.size();
- int iCount = m_vRange.size();
- //*/
- assert(false);
- return;
- }
- long x = vUnNeededFileInxs[i].cx;
- long y = vUnNeededFileInxs[i].cy - 1;
- BLONG cx = m_vRange[x].m_lbeg;
- BLONG cy = m_vRange[y].m_lend;
- if (vUnNeededRanges.size() > 0 && (cx == vUnNeededRanges[vUnNeededRanges.size() - 1].cy))
- {
- vUnNeededRanges[vUnNeededRanges.size() - 1].cy = cy;
- }
- else
- {
- vUnNeededRanges.push_back(CSizeEx(cx, cy));
- }
- }
- // int iCount = vUnNeededRanges.size();
- }
- BLONG CStorageEx::GetTotalLength()
- {
- return m_lTotalLength;
- }
- void CStorageEx::SetReadOnly()
- {
- vector<string> vKeys;
- for (map<string, bool>::iterator it = m_mWHandles.begin(); it != m_mWHandles.end(); it ++)
- vKeys.push_back((*it).first);
- for (int i=0; i<vKeys.size(); i++)
- {
- string strFileName = vKeys[i];
- assert(!strFileName.empty());
- _close(strFileName);
- vector<string>::iterator iter =
- find(m_vHandleBuffer.begin(), m_vHandleBuffer.end(), strFileName);
- if (iter != m_vHandleBuffer.end())
- m_vHandleBuffer.erase(iter);
- }
- }
- void CStorageEx::top_off()
- {
- for (int i=0; i<m_vRange.size(); i++)
- {
- int lLength = m_vRange[i].m_lend - m_vRange[i].m_lbeg;
- if (lLength > m_mTops[m_vRange[i].m_strFileName])
- {
- FILE* pfile = _get_file_handle(m_vRange[i].m_strFileName, true);
- if (!pfile)
- {
- assert(false);
- continue;
- }
- int iRet = fseek(pfile, lLength-1, SEEK_SET);
- assert(!iRet);
- unsigned char cEnd = 0xff;
- iRet = fwrite(&cEnd, sizeof(char), 1, pfile);
- if (iRet != 1)
- {
- assert(false);
- return;
- }
- }
- }
- }
- bool CStorageEx::flush()
- {
- for (map<string, bool>::iterator iter = m_mWHandles.begin(); iter != m_mWHandles.end(); iter ++)
- {
- assert(m_mHandles.find((*iter).first) != m_mHandles.end());
- int iRet = fflush(m_mHandles[(*iter).first]);
- if (iRet)
- {
- assert(false);
- return false;
- }
- }
- return true;
- }
- bool CStorageEx::was_preallocated(BLONG lPos, BLONG lLength)
- {
- assert(lPos >= 0 && lLength >= 0);
- vector<CRange> v;
- _intervals(lPos, lLength, v);
- for (int i=0; i<v.size(); i++)
- {
- if (m_mTops[v[i].m_strFileName] < v[i].m_lend)
- return false;
- }
- return true;
- }
- bool CStorageEx::write(char *pBuf, BLONG lPos, BLONG lAmount)
- {
- assert((lAmount + lPos) <= m_lTotalLength && lPos >= 0 && lAmount >= 0);
- BLONG lwrite = 0;
- vector<CRange> v;
- _intervals(lPos, lAmount, v);
- for (int i=0; i<v.size(); i++)
- {
- FILE* pfile = _get_file_handle(v[i].m_strFileName, true);
- if (!pfile)
- {
- assert(false);
- return false;
- }
- int iRet = fseek(pfile, v[i].m_lbeg, SEEK_SET);
- assert(!iRet);
- BLONG lLen = v[i].m_lend - v[i].m_lbeg;
- iRet = fwrite(pBuf + lwrite, sizeof(char), lLen, pfile);
- if (iRet != lLen)
- {
- if (ENOSPC == errno)
- {
- m_pMain->SetBadMsg("No space left on device");
- return false;
- }
- int i = errno;
- assert(false);
- return false;
- }
- lwrite += lLen;
- }
- assert(lwrite == lAmount);
- return true;
- }
- bool CStorageEx::read(char *pBuf, BLONG lPos, BLONG lAmount, bool bFlushFirst)
- {
- //*
- assert((lAmount + lPos) <= m_lTotalLength && lPos >= 0 && lAmount >= 0);
- BLONG lread = 0;
- vector<CRange> v;
- _intervals(lPos, lAmount, v);
- for (int i=0; i<v.size(); i++)
- {
- FILE* pfile = _get_file_handle(v[i].m_strFileName, false);
- if (!pfile)
- {
- assert(false);
- return false;
- }
- if (bFlushFirst && m_mWHandles.find(v[i].m_strFileName) != m_mWHandles.end())
- {
- int iRet = fflush(pfile);
- if (iRet)
- {
- assert(false);
- return false;
- }
- }
- int iRet = fseek(pfile, v[i].m_lbeg, SEEK_SET);
- assert(!iRet);
- BLONG lLen = v[i].m_lend - v[i].m_lbeg;
- iRet = fread(pBuf+lread, sizeof(char), lLen, pfile);
- if (iRet != lLen)
- {
- TRACE("%d, %d", v[i].m_lend, v[i].m_lbeg);
- assert(iRet == lLen);
- return false;
- }
- lread+= lLen;
- }
- assert(lread == lAmount);
- return true;
- }
- bool CStorageEx::_intervals(BLONG lPos, BLONG lAmount, vector<CStorageEx::CRange>& v)
- {
- assert(lPos >= 0 && lAmount >= 0 && v.empty());
- BLONG lbeg = 0, lend = 0;
- BLONG lstop = lPos + lAmount;
- for (int i=0; i<m_vRange.size(); i++)
- {
- lend = lbeg + (m_vRange[i].m_lend - m_vRange[i].m_lbeg);
- if (lend <= lPos)
- {
- lbeg = lend;
- continue;
- }
- if (lbeg >= lstop)
- break;
- v.push_back(CRange(max(lPos, lbeg) - lbeg, min(lend, lstop) - lbeg, m_vRange[i].m_strFileName));
- lbeg = lend;
- }
- #ifdef _DEBUG
- BLONG lread = 0;
- // TRACE("rn{");
- for (i=0; i<v.size(); i++)
- {
- lread += v[i].m_lend - v[i].m_lbeg;
- // TRACE("(%d, %d)", v[i].m_lbeg, v[i].m_lend);
- }
- // TRACE("}rn");
- assert(lread == lAmount);
- #endif
- return true;
- }
- void CStorageEx::_lock_file(string strFileName, FILE* pfile)
- {
- if (!m_bLockFiles)
- return;
- assert(m_mSizes.find(strFileName) != m_mSizes.end());
- BLONG lLength = m_mSizes[strFileName];
- assert(lLength >= 0);
- int iRet = fseek(pfile, 0, SEEK_SET);
- assert(!iRet);
- iRet = _locking(fileno(pfile), _LK_LOCK, lLength);
- assert(iRet != -1);
- /*
- for (int i=0; i<lLength;)
- {
- int iRet = fseek(pfile, i, SEEK_SET);
- assert(!iRet);
- }
- //*/
- }
- void CStorageEx::_unlock_file(string strFileName, FILE* pfile)
- {
- if (!m_bLockFiles)
- return;
- assert(m_mSizes.find(strFileName) != m_mSizes.end());
- BLONG lLength = m_mSizes[strFileName];
- assert(lLength >= 0);
- int iRet = fseek(pfile, 0, SEEK_SET);
- assert(!iRet);
- iRet = _locking(fileno(pfile), _LK_UNLCK, lLength);
- int iErr = errno;
- assert(iRet != -1);
- }
- FILE* CStorageEx::_get_file_handle(string strFileName, bool bForWrite)
- {
- if (m_mHandles.find(strFileName) != m_mHandles.end())
- {
- if (bForWrite && m_mWHandles.find(strFileName) == m_mWHandles.end())
- {
- _close(strFileName);
- FILE* pfile = _open(strFileName, "rb+");
- if (!pfile)
- {
- assert(false);
- return 0;
- }
- m_mHandles[strFileName] = pfile;
- m_mWHandles[strFileName] = 1;
- _lock_file(strFileName, pfile);
- }
- if (m_bMaxFilesOpen)
- {
- vector<string>::iterator iter =
- find(m_vHandleBuffer.begin(), m_vHandleBuffer.end(), strFileName);
- if (iter != m_vHandleBuffer.end())
- m_vHandleBuffer.erase(iter);
- m_vHandleBuffer.push_back(strFileName);
- }
- }
- else
- {
- if (bForWrite)
- {
- FILE* pfile = _open(strFileName, "rb+");
- if (!pfile)
- {
- assert(false);
- return 0;
- }
- m_mHandles[strFileName] = pfile;
- m_mWHandles[strFileName] = 1;
- _lock_file(strFileName, pfile);
- }
- else
- {
- FILE* pfile = _open(strFileName, "rb");
- if (!pfile)
- {
- assert(false);
- return 0;
- }
- m_mHandles[strFileName] = pfile;
- if (m_bLockWhileReading)
- _lock_file(strFileName, pfile);
- }
- if (m_bMaxFilesOpen)
- {
- m_vHandleBuffer.push_back(strFileName);
- if (m_vHandleBuffer.size() > m_lMaxFilesOpen)
- {
- _close(*m_vHandleBuffer.begin());
- m_vHandleBuffer.erase(m_vHandleBuffer.begin());
- }
- }
- }
- return m_mHandles[strFileName];
- }
- FILE* CStorageEx::_open(string strFileName, string strMode)
- {
- assert(m_mTops.find(strFileName) != m_mTops.end() &&
- m_mTimes.find(strFileName)!= m_mTimes.end());
- if (m_bMaxFilesOpen)
- {
- if (GetFileSize(strFileName) != m_mTops[strFileName] ||
- getfiletime(strFileName) > (m_mTimes[strFileName] + 1))
- {
- assert(false);
- throw string("file (" + strFileName + ") modified by user during downloading");
- return 0;
- }
- }
- return fopen(strFileName.data(), strMode.data());
- }
- void CStorageEx::_close(string strFileName)
- {
- assert(m_mHandles.find(strFileName) != m_mHandles.end());
- FILE* pfile = m_mHandles[strFileName];
- m_mHandles.erase(strFileName);
- if (m_mWHandles.find(strFileName) != m_mWHandles.end())
- {
- m_mWHandles.erase(strFileName);
- _unlock_file(strFileName, pfile);
- m_mTops[strFileName] = GetFileSize(strFileName);
- fclose(pfile);
- m_mTimes[strFileName] = getfiletime(strFileName);
- }
- else
- {
- if (m_bLockWhileReading)
- _unlock_file(strFileName, pfile);
- fclose(pfile);
- }
- }
- time_t CStorageEx::getfiletime(string strFileName)
- {
- FILE* pfile = fopen(strFileName.data(), "rb");
- if (!pfile)
- {
- assert(false);
- return 0; // throw string("truncate file(") + vFiles[i].m_strFilePath + ") error";
- }
- int fh = _fileno(pfile);
- struct _stat buf;
- int result = _fstat( fh, &buf );
- if( result != 0 )
- {
- assert(false);
- return 0;
- }
- time_t tRet = buf.st_mtime;
- fclose(pfile);
- return tRet;
- }