Storage.cpp
上传用户:lds876
上传日期:2013-05-25
资源大小:567k
文件大小:14k
源码类别:

P2P编程

开发平台:

Visual C++

  1. // StorageEx.cpp: implementation of the CStorageEx class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "testbt.h"
  6. #include "Storage.h"
  7. #include "FileBase.h"
  8. #include <sys/stat.h> 
  9. #include <sys/types.h>
  10. #include <sys/locking.h>
  11. #include "DownloaderFeedback.h"
  12. #ifdef _DEBUG
  13. #undef THIS_FILE
  14. static char THIS_FILE[]=__FILE__;
  15. #define new DEBUG_NEW
  16. #endif
  17. //////////////////////////////////////////////////////////////////////
  18. // Construction/Destruction
  19. //////////////////////////////////////////////////////////////////////
  20. CStorageEx::CStorageEx()
  21. {
  22. m_pMain = 0;
  23. m_hevDone = 0;
  24. m_lTotalLength = 0;
  25. m_lMaxFilesOpen = 0;
  26. m_bLockWhileReading = false;
  27. m_bLockFiles = false;
  28. }
  29. CStorageEx::~CStorageEx()
  30. {
  31. Close();
  32. }
  33. void CStorageEx::Close()
  34. {
  35. for (map<string, FILE*>::iterator i=m_mHandles.begin(); i != m_mHandles.end(); i++)
  36. {
  37. string strFileName = (*i).first;
  38. FILE* pfile = (*i).second;
  39. assert(pfile);
  40. if (m_bLockWhileReading || 
  41. m_mWHandles.find(strFileName) != m_mWHandles.end())
  42. {
  43. _unlock_file(strFileName, pfile);
  44. }
  45. int iRet = fclose(pfile);
  46. assert(!iRet);
  47. ferror(pfile);
  48. }
  49. m_vHandleBuffer.clear();
  50. m_mHandles.clear();
  51. m_mWHandles.clear();
  52. m_mSizes.clear();
  53. m_mTimes.clear();
  54. m_vRange.clear();
  55. }
  56. bool CStorageEx::Create(CDownloaderFeedback* pMain, vector<CFileInfo>& vFiles, 
  57. HANDLE hevDone, long lMaxFilesOpen, bool bLockFiles, bool bLockWhileReading)
  58. {
  59. // assert(pMain && hevDone);
  60. m_pMain = pMain;
  61. m_hevDone = hevDone;
  62. m_lMaxFilesOpen = lMaxFilesOpen;
  63. m_bLockWhileReading = bLockWhileReading;
  64. m_bLockFiles = bLockFiles;
  65. try
  66. {
  67. BLONG lTotalLength = 0;
  68. long lNumFiles = 0;
  69. for (int i=0; i<vFiles.size(); i++)
  70. {
  71. if (IsEventSet(m_hevDone))
  72. return true;
  73. if (vFiles[i].m_lFileLength != 0)
  74. {
  75. m_vRange.push_back(CRange(lTotalLength, 
  76. lTotalLength + vFiles[i].m_lFileLength, vFiles[i].m_strFilePath));
  77. lNumFiles ++;
  78. lTotalLength += vFiles[i].m_lFileLength;
  79. BLONG lsize = 0;
  80. if (!_access(vFiles[i].m_strFilePath.data(), 0))
  81. {
  82. lsize = GetFileSize(vFiles[i].m_strFilePath.data());
  83. if (lsize > vFiles[i].m_lFileLength)
  84. {
  85. lsize = vFiles[i].m_lFileLength;
  86. FILE* pfile = fopen(vFiles[i].m_strFilePath.data(), "rb+");
  87. if (!pfile)
  88. {
  89. assert(pfile);
  90. return false; // throw string("truncate file(") + vFiles[i].m_strFilePath + ") error";
  91. }
  92. int fh = _fileno(pfile);
  93. int iRet = chsize(fh, vFiles[i].m_lFileLength);
  94. assert(iRet == 0);
  95. fclose(pfile);
  96. }
  97. }
  98. else // not exist.
  99. {
  100. lsize = 0;
  101. FILE* pfile = fopen(vFiles[i].m_strFilePath.data(), "wb+");
  102. if (!pfile)
  103. {
  104. assert(false);
  105. return false; // throw string("create file(") + vFiles[i].m_strFilePath + ") error";
  106. }
  107. fclose(pfile);
  108. }
  109. m_mTops[vFiles[i].m_strFilePath] = lsize;
  110. m_mSizes[vFiles[i].m_strFilePath] = vFiles[i].m_lFileLength;
  111. m_mTimes[vFiles[i].m_strFilePath] = getfiletime(vFiles[i].m_strFilePath);
  112. }
  113. else // file length = 0.
  114. {
  115. if (!_access(vFiles[i].m_strFilePath.data(), 0))
  116. {
  117. BLONG lsize = GetFileSize(vFiles[i].m_strFilePath.data());
  118. if (lsize > 0)
  119. throw string("file exist length too large, should be zero");
  120. }
  121. else
  122. {
  123. }
  124. }
  125. } // end for
  126. // for (i =0; i<m_vRange.size(); i++)
  127. // m_vBegins.push_back(m_vRange[i].m_lbeg);
  128. m_lTotalLength = lTotalLength;
  129. m_bMaxFilesOpen = (m_lMaxFilesOpen > 0 && (lNumFiles > m_lMaxFilesOpen));
  130. } // end try
  131. catch (string e)
  132. {
  133. throw e;
  134. }
  135. return true;
  136. }
  137. bool CStorageEx::GetFilesRange(vector<long>& vRangeHoles, vector<long>& vFileOffset, long lPieceLen)
  138. {
  139. if (!lPieceLen)
  140. return false;
  141. vRangeHoles.clear();
  142. vFileOffset.clear();
  143. vRangeHoles.push_back(0);
  144. vFileOffset.push_back(0);
  145. BLONG lbeg = 0, lend = 0;
  146. for (int i=0; i<m_vRange.size(); i++)
  147. {
  148. lbeg = m_vRange[i].m_lbeg;
  149. if ((lbeg - lend) > lPieceLen)
  150. {
  151. vFileOffset.push_back(lbeg % lPieceLen);
  152. vRangeHoles.push_back(lbeg / lPieceLen);
  153. lend = lbeg;
  154. }
  155. }
  156. #ifdef _DEBUG
  157. TRACE("rn**vRangeHolesIndex : {rn");
  158. for (i=0; i<vRangeHoles.size();i++)
  159. {
  160. TRACE("%d, ", vRangeHoles[i]);
  161. }
  162. TRACE("}rn");
  163. #endif
  164. return true;
  165. }
  166. void CStorageEx::GetUnNeededRanges(const vector<CSize>& vUnNeededFileInxs, vector<CSizeEx>& vUnNeededRanges) const
  167. {
  168. vUnNeededRanges.clear();
  169. for (int i=0; i<vUnNeededFileInxs.size(); i++)
  170. {
  171. assert(vUnNeededFileInxs[i].cy > vUnNeededFileInxs[i].cx);
  172. assert(vUnNeededFileInxs[i].cx >= 0);
  173. if((vUnNeededFileInxs[i].cy - 1) >= m_vRange.size())
  174. {
  175. /*
  176. CSize lData[1000] = {CSize(0, 0)};
  177. for (int j=0; j<vUnNeededFileInxs.size(); j++)
  178. {
  179. lData[j] = vUnNeededFileInxs[j];
  180. }
  181. long lsize  = vUnNeededFileInxs.size();
  182. int iCount = m_vRange.size();
  183. //*/
  184. assert(false);
  185. return;
  186. }
  187. long x = vUnNeededFileInxs[i].cx;
  188. long y = vUnNeededFileInxs[i].cy - 1;
  189. BLONG cx = m_vRange[x].m_lbeg;
  190. BLONG cy = m_vRange[y].m_lend;
  191. if (vUnNeededRanges.size() > 0 && (cx == vUnNeededRanges[vUnNeededRanges.size() - 1].cy))
  192. {
  193. vUnNeededRanges[vUnNeededRanges.size() - 1].cy = cy;
  194. }
  195. else
  196. {
  197. vUnNeededRanges.push_back(CSizeEx(cx, cy));
  198. }
  199. }
  200. // int iCount = vUnNeededRanges.size();
  201. }
  202. BLONG CStorageEx::GetTotalLength()
  203. {
  204. return m_lTotalLength;
  205. }
  206. void CStorageEx::SetReadOnly()
  207. {
  208. vector<string> vKeys;
  209. for (map<string, bool>::iterator it = m_mWHandles.begin(); it != m_mWHandles.end(); it ++)
  210. vKeys.push_back((*it).first);
  211. for (int i=0; i<vKeys.size(); i++)
  212. {
  213. string strFileName = vKeys[i];
  214. assert(!strFileName.empty());
  215. _close(strFileName);
  216. vector<string>::iterator iter = 
  217. find(m_vHandleBuffer.begin(), m_vHandleBuffer.end(), strFileName);
  218. if (iter != m_vHandleBuffer.end())
  219. m_vHandleBuffer.erase(iter);
  220. }
  221. }
  222. void CStorageEx::top_off()
  223. {
  224. for (int i=0; i<m_vRange.size(); i++)
  225. {
  226. int lLength = m_vRange[i].m_lend - m_vRange[i].m_lbeg;
  227. if (lLength > m_mTops[m_vRange[i].m_strFileName])
  228. {
  229. FILE* pfile = _get_file_handle(m_vRange[i].m_strFileName, true);
  230. if (!pfile)
  231. {
  232. assert(false);
  233. continue;
  234. }
  235. int iRet = fseek(pfile, lLength-1, SEEK_SET);
  236. assert(!iRet);
  237. unsigned char cEnd = 0xff;
  238. iRet = fwrite(&cEnd, sizeof(char), 1, pfile);
  239. if (iRet != 1)
  240. {
  241. assert(false);
  242. return;
  243. }
  244. }
  245. }
  246. }
  247. bool CStorageEx::flush()
  248. {
  249. for (map<string, bool>::iterator iter = m_mWHandles.begin(); iter != m_mWHandles.end(); iter ++)
  250. {
  251. assert(m_mHandles.find((*iter).first) != m_mHandles.end());
  252. int iRet = fflush(m_mHandles[(*iter).first]);
  253. if (iRet)
  254. {
  255. assert(false);
  256. return false;
  257. }
  258. }
  259. return true;
  260. }
  261. bool CStorageEx::was_preallocated(BLONG lPos, BLONG lLength)
  262. {
  263. assert(lPos >= 0 && lLength >= 0);
  264. vector<CRange> v;
  265. _intervals(lPos, lLength, v);
  266. for (int i=0; i<v.size(); i++)
  267. {
  268. if (m_mTops[v[i].m_strFileName] < v[i].m_lend)
  269. return false;
  270. }
  271. return true;
  272. }
  273. bool CStorageEx::write(char *pBuf, BLONG lPos, BLONG lAmount)
  274. {
  275. assert((lAmount + lPos) <= m_lTotalLength && lPos >= 0 && lAmount >= 0);
  276. BLONG lwrite = 0;
  277. vector<CRange> v;
  278. _intervals(lPos, lAmount, v);
  279. for (int i=0; i<v.size(); i++)
  280. {
  281. FILE* pfile = _get_file_handle(v[i].m_strFileName, true);
  282. if (!pfile)
  283. {
  284. assert(false);
  285. return false;
  286. }
  287. int iRet = fseek(pfile, v[i].m_lbeg, SEEK_SET);
  288. assert(!iRet);
  289. BLONG lLen = v[i].m_lend - v[i].m_lbeg;
  290. iRet = fwrite(pBuf + lwrite, sizeof(char), lLen, pfile);
  291. if (iRet != lLen)
  292. {
  293. if (ENOSPC == errno)
  294. {
  295. m_pMain->SetBadMsg("No space left on device");
  296. return false;
  297. }
  298. int i = errno;
  299. assert(false);
  300. return false;
  301. }
  302. lwrite += lLen;
  303. }
  304. assert(lwrite == lAmount);
  305. return true;
  306. }
  307. bool CStorageEx::read(char *pBuf, BLONG lPos, BLONG lAmount, bool bFlushFirst)
  308. {
  309. //*
  310. assert((lAmount + lPos) <= m_lTotalLength && lPos >= 0 && lAmount >= 0);
  311. BLONG lread = 0;
  312. vector<CRange> v;
  313. _intervals(lPos, lAmount, v);
  314. for (int i=0; i<v.size(); i++)
  315. {
  316. FILE* pfile = _get_file_handle(v[i].m_strFileName, false);
  317. if (!pfile)
  318. {
  319. assert(false);
  320. return false;
  321. }
  322. if (bFlushFirst && m_mWHandles.find(v[i].m_strFileName) != m_mWHandles.end())
  323. {
  324. int iRet = fflush(pfile);
  325. if (iRet)
  326. {
  327. assert(false);
  328. return false;
  329. }
  330. }
  331. int iRet = fseek(pfile, v[i].m_lbeg, SEEK_SET);
  332. assert(!iRet);
  333. BLONG lLen = v[i].m_lend - v[i].m_lbeg;
  334. iRet = fread(pBuf+lread, sizeof(char), lLen, pfile);
  335. if (iRet != lLen)
  336. {
  337. TRACE("%d, %d", v[i].m_lend, v[i].m_lbeg);
  338. assert(iRet == lLen);
  339. return false;
  340. }
  341. lread+= lLen;
  342. }
  343. assert(lread == lAmount);
  344. return true;
  345. }
  346. bool CStorageEx::_intervals(BLONG lPos, BLONG lAmount, vector<CStorageEx::CRange>& v)
  347. {
  348. assert(lPos >= 0 && lAmount >= 0 && v.empty());
  349. BLONG lbeg = 0, lend = 0;
  350. BLONG lstop = lPos + lAmount;
  351. for (int i=0; i<m_vRange.size(); i++)
  352. {
  353. lend = lbeg + (m_vRange[i].m_lend - m_vRange[i].m_lbeg);
  354. if (lend <= lPos)
  355. {
  356. lbeg = lend;
  357. continue;
  358. }
  359. if (lbeg >= lstop)
  360. break;
  361. v.push_back(CRange(max(lPos, lbeg) - lbeg, min(lend, lstop) - lbeg, m_vRange[i].m_strFileName));
  362. lbeg = lend;
  363. }
  364. #ifdef _DEBUG
  365. BLONG lread = 0;
  366. // TRACE("rn{");
  367. for (i=0; i<v.size(); i++)
  368. {
  369. lread += v[i].m_lend - v[i].m_lbeg;
  370. // TRACE("(%d, %d)",  v[i].m_lbeg, v[i].m_lend);
  371. }
  372. // TRACE("}rn");
  373. assert(lread  == lAmount);
  374. #endif
  375. return true;
  376. }
  377. void CStorageEx::_lock_file(string strFileName, FILE* pfile)
  378. {
  379. if (!m_bLockFiles)
  380. return;
  381. assert(m_mSizes.find(strFileName) != m_mSizes.end());
  382. BLONG lLength = m_mSizes[strFileName];
  383. assert(lLength >= 0);
  384. int iRet = fseek(pfile, 0, SEEK_SET);
  385. assert(!iRet);
  386. iRet = _locking(fileno(pfile), _LK_LOCK, lLength);
  387. assert(iRet != -1);
  388. /*
  389. for (int i=0; i<lLength;)
  390. {
  391. int iRet = fseek(pfile, i, SEEK_SET);
  392. assert(!iRet);  
  393. }
  394. //*/
  395. }
  396. void CStorageEx::_unlock_file(string strFileName, FILE* pfile)
  397. {
  398. if (!m_bLockFiles)
  399. return;
  400. assert(m_mSizes.find(strFileName) != m_mSizes.end());
  401. BLONG lLength = m_mSizes[strFileName];
  402. assert(lLength >= 0);
  403. int iRet = fseek(pfile, 0, SEEK_SET);
  404. assert(!iRet);
  405. iRet = _locking(fileno(pfile), _LK_UNLCK, lLength);
  406. int iErr = errno;
  407. assert(iRet != -1);
  408. }
  409. FILE* CStorageEx::_get_file_handle(string strFileName, bool bForWrite)
  410. {
  411. if (m_mHandles.find(strFileName) != m_mHandles.end())
  412. {
  413. if (bForWrite && m_mWHandles.find(strFileName) == m_mWHandles.end())
  414. {
  415. _close(strFileName);
  416. FILE* pfile = _open(strFileName, "rb+");
  417. if (!pfile)
  418. {
  419. assert(false);
  420. return 0;
  421. }
  422. m_mHandles[strFileName] = pfile;
  423. m_mWHandles[strFileName] = 1;
  424. _lock_file(strFileName, pfile);
  425. }
  426. if (m_bMaxFilesOpen)
  427. {
  428. vector<string>::iterator iter = 
  429. find(m_vHandleBuffer.begin(), m_vHandleBuffer.end(), strFileName);
  430. if (iter != m_vHandleBuffer.end())
  431. m_vHandleBuffer.erase(iter);
  432. m_vHandleBuffer.push_back(strFileName);
  433. }
  434. }
  435. else
  436. {
  437. if (bForWrite)
  438. {
  439. FILE* pfile = _open(strFileName, "rb+");
  440. if (!pfile)
  441. {
  442. assert(false);
  443. return 0;
  444. }
  445. m_mHandles[strFileName] = pfile;
  446. m_mWHandles[strFileName] = 1;
  447. _lock_file(strFileName, pfile);
  448. }
  449. else
  450. {
  451. FILE* pfile = _open(strFileName, "rb");
  452. if (!pfile)
  453. {
  454. assert(false);
  455. return 0;
  456. }
  457. m_mHandles[strFileName] = pfile;
  458. if (m_bLockWhileReading)
  459. _lock_file(strFileName, pfile);
  460. }
  461. if (m_bMaxFilesOpen)
  462. {
  463. m_vHandleBuffer.push_back(strFileName);
  464. if (m_vHandleBuffer.size() > m_lMaxFilesOpen)
  465. {
  466. _close(*m_vHandleBuffer.begin());
  467. m_vHandleBuffer.erase(m_vHandleBuffer.begin());
  468. }
  469. }
  470. }
  471. return m_mHandles[strFileName];
  472. }
  473. FILE* CStorageEx::_open(string strFileName, string strMode)
  474. {
  475. assert(m_mTops.find(strFileName) != m_mTops.end() && 
  476. m_mTimes.find(strFileName)!= m_mTimes.end());
  477. if (m_bMaxFilesOpen)
  478. {
  479. if (GetFileSize(strFileName) != m_mTops[strFileName] ||
  480. getfiletime(strFileName) > (m_mTimes[strFileName] + 1))
  481. {
  482. assert(false);
  483. throw string("file (" + strFileName + ") modified by user during downloading");
  484. return 0;
  485. }
  486. }
  487. return fopen(strFileName.data(), strMode.data());
  488. }
  489. void CStorageEx::_close(string strFileName)
  490. {
  491. assert(m_mHandles.find(strFileName) != m_mHandles.end());
  492. FILE* pfile = m_mHandles[strFileName];
  493. m_mHandles.erase(strFileName);
  494. if (m_mWHandles.find(strFileName) != m_mWHandles.end())
  495. {
  496. m_mWHandles.erase(strFileName);
  497. _unlock_file(strFileName, pfile);
  498. m_mTops[strFileName] = GetFileSize(strFileName);
  499. fclose(pfile);
  500. m_mTimes[strFileName] = getfiletime(strFileName);
  501. }
  502. else
  503. {
  504. if (m_bLockWhileReading)
  505. _unlock_file(strFileName, pfile);
  506. fclose(pfile);
  507. }
  508. }
  509. time_t CStorageEx::getfiletime(string strFileName)
  510. {
  511. FILE* pfile = fopen(strFileName.data(), "rb");
  512. if (!pfile)
  513. {
  514. assert(false);
  515. return 0; // throw string("truncate file(") + vFiles[i].m_strFilePath + ") error";
  516. }
  517. int fh = _fileno(pfile);
  518. struct _stat buf;
  519. int result = _fstat( fh, &buf );
  520. if( result != 0 )
  521. {
  522. assert(false);
  523. return 0;
  524. }
  525. time_t tRet = buf.st_mtime;
  526. fclose(pfile);
  527. return tRet;
  528. }