PageRenderTime 54ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/libretroshare/src/dbase/findex.cc

https://gitlab.com/g10h4ck/RetroShare
C++ | 1514 lines | 1133 code | 232 blank | 149 comment | 195 complexity | 343137dd12c4bf742891c1edfbd885fd MD5 | raw file
Possible License(s): 0BSD, GPL-2.0, AGPL-1.0
  1. /*
  2. * RetroShare FileCache Module: findex.cc
  3. *
  4. * Copyright 2004-2007 by Robert Fernie, Kefei Zhou.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Library General Public
  8. * License Version 2 as published by the Free Software Foundation.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Library General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Library General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  18. * USA.
  19. *
  20. * Please report all bugs and problems to "retroshare@lunamutt.com".
  21. *
  22. */
  23. #include <util/rswin.h>
  24. #include <util/rsmemory.h>
  25. #include "dbase/findex.h"
  26. #include "retroshare/rsexpr.h"
  27. #include "util/rsdir.h"
  28. #include "util/rsstring.h"
  29. #include "util/rscompress.h"
  30. #include <assert.h>
  31. #include <stdlib.h>
  32. #include <algorithm>
  33. #include <iostream>
  34. #ifdef __MAC_10_10
  35. #include <unordered_set>
  36. #else
  37. #include <tr1/unordered_set>
  38. #endif
  39. #include <iomanip>
  40. #include <fstream>
  41. #include <sys/stat.h>
  42. #include <errno.h>
  43. #include <time.h>
  44. #include <openssl/sha.h>
  45. #include <util/rsthreads.h>
  46. // This char is used to separate fields in the file list cache. It is supposed to be
  47. // sufficiently safe on all systems.
  48. //
  49. static const char FILE_CACHE_SEPARATOR_CHAR = '|' ;
  50. /****
  51. * #define FI_DEBUG 1
  52. * #define FI_DEBUG_ALL 1
  53. ****/
  54. static RsMutex FIndexPtrMtx("FIndexPtrMtx") ;
  55. #ifdef __MAC_10_10
  56. std::unordered_set<void*> FileIndex::_pointers ;
  57. #else
  58. std::tr1::unordered_set<void*> FileIndex::_pointers ;
  59. #endif
  60. void FileIndex::registerEntry(void*p)
  61. {
  62. RsStackMutex m(FIndexPtrMtx) ;
  63. _pointers.insert(p) ;
  64. }
  65. void FileIndex::unregisterEntry(void*p)
  66. {
  67. RsStackMutex m(FIndexPtrMtx) ;
  68. _pointers.erase(p) ;
  69. }
  70. bool FileIndex::isValid(void*p)
  71. {
  72. RsStackMutex m(FIndexPtrMtx) ;
  73. return _pointers.find(p) != _pointers.end() ;
  74. }
  75. DirEntry::~DirEntry()
  76. {
  77. /* cleanup */
  78. std::map<std::string, DirEntry *>::iterator dit;
  79. std::map<std::string, FileEntry *>::iterator fit;
  80. for(dit = subdirs.begin(); dit != subdirs.end(); ++dit)
  81. {
  82. FileIndex::unregisterEntry((void*)dit->second) ;
  83. delete (dit->second);
  84. }
  85. subdirs.clear();
  86. for(fit = files.begin(); fit != files.end(); ++fit)
  87. {
  88. FileIndex::unregisterEntry((void*)fit->second) ;
  89. delete (fit->second);
  90. }
  91. files.clear();
  92. }
  93. int DirEntry::checkParentPointers()
  94. {
  95. #ifdef FI_DEBUG
  96. updateChildRows();
  97. std::map<std::string, DirEntry *>::iterator dit;
  98. for(dit = subdirs.begin(); dit != subdirs.end(); ++dit)
  99. {
  100. /* debug check */
  101. (dit->second)->checkParentPointers();
  102. }
  103. #endif
  104. return 1;
  105. }
  106. int DirEntry::updateChildRows()
  107. {
  108. /* iterate through children and set row (parent should be good) */
  109. std::map<std::string, DirEntry *>::iterator dit;
  110. std::map<std::string, FileEntry *>::iterator fit;
  111. int i = 0;
  112. for(dit = subdirs.begin(); dit != subdirs.end(); ++dit)
  113. {
  114. #ifdef FI_DEBUG
  115. /* debug check */
  116. if ((dit->second)->parent != this)
  117. {
  118. std::cerr << "DirEntry::updateChildRows()";
  119. std::cerr << "****WARNING subdir Parent pointer invalid!";
  120. std::cerr << std::endl;
  121. (dit->second)->parent = this;
  122. }
  123. #endif
  124. (dit->second)->row = i++;
  125. }
  126. for(fit = files.begin(); fit != files.end(); ++fit)
  127. {
  128. #ifdef FI_DEBUG
  129. /* debug check */
  130. if ((fit->second)->parent != this)
  131. {
  132. std::cerr << "DirEntry::updateChildRows()";
  133. std::cerr << "****WARNING file Parent pointer invalid!";
  134. std::cerr << std::endl;
  135. (fit->second)->parent = this;
  136. }
  137. #endif
  138. (fit->second)->row = i++;
  139. }
  140. return 1;
  141. }
  142. int DirEntry::removeDir(const std::string& name)
  143. {
  144. /* if it doesn't exist - add */
  145. std::map<std::string, DirEntry *>::iterator it;
  146. DirEntry *ndir = NULL;
  147. if (subdirs.end() != (it = subdirs.find(name)))
  148. {
  149. #ifdef FI_DEBUG_ALL
  150. std::cerr << "DirEntry::removeDir() Cleaning up dir: " << name;
  151. std::cerr << std::endl;
  152. #endif
  153. ndir = (it->second);
  154. subdirs.erase(it);
  155. FileIndex::unregisterEntry((void*)ndir) ;
  156. delete ndir;
  157. /* update row counters */
  158. updateChildRows();
  159. return 1;
  160. }
  161. #ifdef FI_DEBUG
  162. std::cerr << "DirEntry::removeDir() missing Entry: " << name;
  163. std::cerr << std::endl;
  164. #endif
  165. return 0;
  166. }
  167. int DirEntry::removeFile(const std::string& name)
  168. {
  169. /* if it doesn't exist - add */
  170. std::map<std::string, FileEntry *>::iterator it;
  171. FileEntry *nfile = NULL;
  172. if (files.end() != (it = files.find(name)))
  173. {
  174. #ifdef FI_DEBUG_ALL
  175. std::cerr << "DirEntry::removeFile() removing File: " << name;
  176. std::cerr << std::endl;
  177. #endif
  178. nfile = (it->second);
  179. files.erase(it);
  180. FileIndex::unregisterEntry((void*)nfile) ;
  181. delete nfile;
  182. /* update row counters */
  183. updateChildRows();
  184. return 1;
  185. }
  186. #ifdef FI_DEBUG
  187. std::cerr << "DirEntry::removeFile() missing Entry: " << name;
  188. std::cerr << std::endl;
  189. #endif
  190. return 0;
  191. }
  192. int DirEntry::removeOldDir(const std::string& name, time_t old)
  193. {
  194. std::map<std::string, DirEntry *>::iterator it;
  195. DirEntry *ndir = NULL;
  196. if (subdirs.end() != (it = subdirs.find(name)))
  197. {
  198. ndir = (it->second);
  199. if (ndir->updtime < old)
  200. {
  201. #ifdef FI_DEBUG_ALL
  202. std::cerr << "DirEntry::removeOldDir() Removing Old dir: " << name;
  203. std::cerr << std::endl;
  204. #endif
  205. subdirs.erase(it);
  206. FileIndex::unregisterEntry((void*)ndir) ;
  207. delete ndir;
  208. /* update row counters */
  209. updateChildRows();
  210. return 1;
  211. }
  212. #ifdef FI_DEBUG_ALL
  213. std::cerr << "DirEntry::removeOldDir() Keeping UptoDate dir: " << name;
  214. std::cerr << std::endl;
  215. #endif
  216. return 0;
  217. }
  218. #ifdef FI_DEBUG
  219. std::cerr << "DirEntry::removeDir() missing Entry: " << name;
  220. std::cerr << std::endl;
  221. #endif
  222. return 0;
  223. }
  224. int DirEntry::removeOldEntries(time_t old, bool recursive)
  225. {
  226. /* remove old dirs from our lists -> then do children and files */
  227. /* get all dirs with old time */
  228. std::list<DirEntry *> removeList;
  229. std::map<std::string, DirEntry *>::iterator it;
  230. for(it = subdirs.begin(); it != subdirs.end(); ++it)
  231. {
  232. if ((it->second)->updtime < old)
  233. {
  234. removeList.push_back(it->second);
  235. }
  236. }
  237. int count = removeList.size();
  238. /* now remove the old entries */
  239. std::list<DirEntry *>::iterator rit;
  240. for(rit = removeList.begin(); rit != removeList.end(); ++rit)
  241. {
  242. removeDir((*rit)->name);
  243. }
  244. if (recursive)
  245. {
  246. /* now handle children */
  247. for(it = subdirs.begin(); it != subdirs.end(); ++it)
  248. {
  249. count += (it->second)->removeOldEntries(old, recursive);
  250. }
  251. }
  252. /* now handle files similarly */
  253. std::list<FileEntry *> removeFileList;
  254. std::map<std::string, FileEntry *>::iterator fit;
  255. for(fit = files.begin(); fit != files.end(); ++fit)
  256. {
  257. if ((fit->second)->updtime < old)
  258. {
  259. removeFileList.push_back(fit->second);
  260. }
  261. }
  262. count += removeFileList.size();
  263. /* now remove the old entries */
  264. std::list<FileEntry *>::iterator rfit;
  265. for(rfit = removeFileList.begin(); rfit != removeFileList.end(); ++rfit)
  266. {
  267. removeFile((*rfit)->name);
  268. }
  269. return count;
  270. }
  271. DirEntry *DirEntry::findOldDirectory(time_t old)
  272. {
  273. /* check if one of our directories is old ...
  274. */
  275. /* get all dirs with old time */
  276. std::map<std::string, DirEntry *>::iterator it;
  277. for(it = subdirs.begin(); it != subdirs.end(); ++it)
  278. {
  279. if ((it->second)->updtime < old)
  280. {
  281. return (it->second);
  282. }
  283. }
  284. /*
  285. * else check chlidren.
  286. */
  287. for(it = subdirs.begin(); it != subdirs.end(); ++it)
  288. {
  289. DirEntry *olddir = (it->second)->findOldDirectory(old);
  290. if (olddir)
  291. {
  292. return olddir;
  293. }
  294. }
  295. return NULL;
  296. }
  297. DirEntry *DirEntry::findDirectory(const std::string& fpath)
  298. {
  299. std::string nextdir = RsDirUtil::getRootDir(fpath);
  300. std::map<std::string, DirEntry *>::iterator it;
  301. if (subdirs.end() == (it = subdirs.find(nextdir)))
  302. {
  303. #ifdef FI_DEBUG
  304. std::cerr << "DirEntry::findDirectory() Missing subdir:";
  305. std::cerr << "\"" << nextdir << "\"";
  306. std::cerr << std::endl;
  307. #endif
  308. return NULL;
  309. }
  310. std::string rempath = RsDirUtil::removeRootDir(fpath);
  311. if (rempath == "")
  312. {
  313. return it->second;
  314. }
  315. // Adding more lenient directory look up.
  316. // returns lower directory to fpath is a FILE.
  317. DirEntry *subdir = (it->second)->findDirectory(rempath);
  318. if (subdir)
  319. return subdir;
  320. else
  321. return it->second;
  322. }
  323. int DirEntry::updateDirectories(const std::string& fpath, int new_pop, int new_modtime)
  324. {
  325. int ret = 1;
  326. if (path != "") /* if not there -> continue down tree */
  327. {
  328. std::string nextdir = RsDirUtil::getRootDir(fpath);
  329. std::map<std::string, DirEntry *>::iterator it;
  330. if (subdirs.end() == (it = subdirs.find(nextdir)))
  331. {
  332. return 0;
  333. }
  334. std::string rempath = RsDirUtil::removeRootDir(fpath);
  335. ret = (it->second)->updateDirectories(rempath, new_pop, new_modtime);
  336. }
  337. if (ret) /* if full path is okay -> update and return ok */
  338. {
  339. /* this is assumes that pop always increases! */
  340. if (new_pop > pop)
  341. {
  342. pop = new_pop;
  343. }
  344. if (new_modtime > modtime)
  345. {
  346. modtime = new_modtime;
  347. }
  348. }
  349. return ret;
  350. }
  351. DirEntry *DirEntry::updateDir(const FileEntry& fe, time_t utime)
  352. {
  353. /* if it doesn't exist - add */
  354. std::map<std::string, DirEntry *>::iterator it;
  355. DirEntry *ndir = NULL;
  356. if (subdirs.end() == (it = subdirs.find(fe.name)))
  357. {
  358. #ifdef FI_DEBUG_ALL
  359. std::cerr << "DirEntry::updateDir() Adding Entry";
  360. std::cerr << std::endl;
  361. #endif
  362. ndir = new DirEntry();
  363. FileIndex::registerEntry((void*)ndir) ;
  364. ndir -> parent = this;
  365. ndir -> path = path + "/" + fe.name;
  366. ndir -> name = fe.name;
  367. ndir -> pop = 0;
  368. ndir -> modtime = 0;
  369. ndir -> updtime = utime;
  370. subdirs[fe.name] = ndir;
  371. /* update row counters */
  372. updateChildRows();
  373. return ndir;
  374. }
  375. #ifdef FI_DEBUG_ALL
  376. std::cerr << "DirEntry::updateDir() Updating Entry";
  377. std::cerr << std::endl;
  378. #endif
  379. /* update utime */
  380. ndir = (it->second);
  381. ndir->updtime = utime;
  382. return ndir;
  383. }
  384. FileEntry *DirEntry::updateFile(const FileEntry& fe, time_t utime)
  385. {
  386. /* if it doesn't exist - add */
  387. std::map<std::string, FileEntry *>::iterator it;
  388. FileEntry *nfile = NULL;
  389. if (files.end() == (it = files.find(fe.name)))
  390. {
  391. #ifdef FI_DEBUG_ALL
  392. std::cerr << "DirEntry::updateFile() Adding Entry";
  393. std::cerr << std::endl;
  394. #endif
  395. nfile = new FileEntry();
  396. FileIndex::registerEntry((void*)nfile) ;
  397. nfile -> parent = this;
  398. nfile -> name = fe.name;
  399. nfile -> hash = fe.hash;
  400. nfile -> size = fe.size;
  401. nfile -> pop = 0;
  402. nfile -> modtime = fe.modtime;
  403. nfile -> updtime = utime;
  404. files[fe.name] = nfile;
  405. /* update row counters */
  406. updateChildRows();
  407. return nfile;
  408. }
  409. #ifdef FI_DEBUG_ALL
  410. std::cerr << "DirEntry::updateFile() Updating Entry";
  411. std::cerr << std::endl;
  412. #endif
  413. /* update utime */
  414. nfile = (it->second);
  415. nfile -> parent = this;
  416. nfile -> name = fe.name;
  417. nfile -> hash = fe.hash;
  418. nfile -> size = fe.size;
  419. nfile -> modtime = fe.modtime;
  420. nfile -> updtime = utime;
  421. //nfile -> pop = 0; // not handled here.
  422. return nfile;
  423. }
  424. int FileEntry::print(std::string &out)
  425. {
  426. /* print this dir, then subdirs, then files */
  427. rs_sprintf_append(out, "file %03d [%ld/%ld] : ", row, updtime, modtime);
  428. if (parent)
  429. out += parent->path;
  430. else
  431. out += "[MISSING PARENT]";
  432. rs_sprintf_append(out, " %s [ s: %lld ] ==> [ %s ]\n", name.c_str(), size, hash.toStdString().c_str());
  433. return 1;
  434. }
  435. int DirEntry::print(std::string &out)
  436. {
  437. /* print this dir, then subdirs, then files */
  438. rs_sprintf_append(out, "dir %03d [%ld] : %s\n", row, updtime, path.c_str());
  439. std::map<std::string, DirEntry *>::iterator it;
  440. for(it = subdirs.begin(); it != subdirs.end(); ++it)
  441. {
  442. (it->second)->print(out);
  443. }
  444. std::map<std::string, FileEntry *>::iterator fit;
  445. for(fit = files.begin(); fit != files.end(); ++fit)
  446. {
  447. (fit->second)->print(out);
  448. }
  449. return 1;
  450. }
  451. FileIndex::FileIndex(const RsPeerId& pid)
  452. {
  453. root = new PersonEntry(pid);
  454. registerEntry(root) ;
  455. _file_hashes.clear() ;
  456. }
  457. FileIndex::~FileIndex()
  458. {
  459. FileIndex::unregisterEntry((void*)root) ;
  460. delete root;
  461. }
  462. int FileIndex::setRootDirectories(const std::list<std::string> &inlist, time_t updtime)
  463. {
  464. /* set update time to zero */
  465. std::map<std::string, DirEntry *>::iterator it;
  466. for(it = root->subdirs.begin(); it != root->subdirs.end(); ++it)
  467. {
  468. (it->second)->updtime = 0;
  469. }
  470. std::list<std::string>::const_iterator ait;
  471. FileEntry fe;
  472. time_t utime = 1;
  473. for(ait = inlist.begin(); ait != inlist.end(); ++ait)
  474. {
  475. fe.name = (*ait);
  476. /* see if it exists */
  477. root->updateDir(fe, utime);
  478. }
  479. /* remove all dirs with zero time (non recursive) */
  480. int cleanedCount = root->removeOldEntries(utime, false);
  481. /* now flag remaining directories with correct update time */
  482. for(it = root->subdirs.begin(); it != root->subdirs.end(); ++it)
  483. {
  484. (it->second)->updtime = updtime;
  485. }
  486. // update file hash index.
  487. updateHashIndex() ;
  488. return cleanedCount;
  489. }
  490. void FileIndex::updateHashIndex()
  491. {
  492. _file_hashes.clear() ;
  493. recursUpdateHashIndex(root) ;
  494. }
  495. void FileIndex::recursUpdateHashIndex(DirEntry *dir)
  496. {
  497. for(std::map<std::string,DirEntry*>::iterator it(dir->subdirs.begin());it!=dir->subdirs.end();++it)
  498. recursUpdateHashIndex(it->second) ;
  499. for(std::map<std::string,FileEntry*>::iterator it(dir->files.begin());it!=dir->files.end();++it)
  500. _file_hashes[it->second->hash] = it->second ;
  501. }
  502. void FileIndex::updateMaxModTime()
  503. {
  504. RecursUpdateMaxModTime(root) ;
  505. }
  506. void FileIndex::RecursUpdateMaxModTime(DirEntry *dir)
  507. {
  508. time_t max_mod_t = 0 ;
  509. for(std::map<std::string,DirEntry*>::iterator it(dir->subdirs.begin());it!=dir->subdirs.end();++it)
  510. {
  511. RecursUpdateMaxModTime(it->second) ;
  512. max_mod_t = std::max(max_mod_t, it->second->most_recent_time) ;
  513. }
  514. for(std::map<std::string,FileEntry*>::iterator it(dir->files.begin());it!=dir->files.end();++it)
  515. max_mod_t = std::max(max_mod_t, it->second->modtime) ;
  516. dir->most_recent_time = max_mod_t ;
  517. }
  518. int FileIndex::getRootDirectories(std::list<std::string> &outlist)
  519. {
  520. /* set update time to zero */
  521. std::map<std::string, DirEntry *>::iterator it;
  522. for(it = root->subdirs.begin(); it != root->subdirs.end(); ++it)
  523. {
  524. outlist.push_back(it->first);
  525. }
  526. return 1;
  527. }
  528. /* update (index building) */
  529. DirEntry *FileIndex::updateDirEntry(const std::string& fpath, const FileEntry& fe, time_t utime)
  530. {
  531. /* path is to parent */
  532. #ifdef FI_DEBUG_ALL
  533. std::cerr << "FileIndex::updateDirEntry() Path: \"";
  534. std::cerr << fpath << "\"" << " + \"" << fe.name << "\"";
  535. std::cerr << std::endl;
  536. #endif
  537. DirEntry *parent = NULL;
  538. if (fpath == "")
  539. {
  540. parent = root;
  541. }
  542. else
  543. {
  544. parent = root->findDirectory(fpath);
  545. }
  546. if (!parent) {
  547. #ifdef FI_DEBUG
  548. std::cerr << "FileIndex::updateDirEntry() NULL parent";
  549. std::cerr << std::endl;
  550. #endif
  551. return NULL;
  552. }
  553. return parent -> updateDir(fe, utime);
  554. }
  555. FileEntry *FileIndex::updateFileEntry(const std::string& fpath, const FileEntry& fe, time_t utime)
  556. {
  557. /* path is to parent */
  558. #ifdef FI_DEBUG_ALL
  559. std::cerr << "FileIndex::updateFileEntry() Path: \"";
  560. std::cerr << fpath << "\"" << " + \"" << fe.name << "\"";
  561. std::cerr << std::endl;
  562. #endif
  563. DirEntry *parent = root->findDirectory(fpath);
  564. if (!parent) {
  565. #ifdef FI_DEBUG
  566. std::cerr << "FileIndex::updateFileEntry() NULL parent";
  567. std::cerr << std::endl;
  568. #endif
  569. return NULL;
  570. }
  571. return parent -> updateFile(fe, utime);
  572. }
  573. DirEntry *FileIndex::findOldDirectory(time_t old) /* finds directories older than old */
  574. {
  575. DirEntry *olddir = root->findOldDirectory(old);
  576. #ifdef FI_DEBUG
  577. std::cerr << "FileIndex::findOldDirectory(" << old << ") -> ";
  578. if (olddir)
  579. {
  580. std::cerr << olddir->path;
  581. }
  582. else
  583. {
  584. std::cerr << "NONE";
  585. }
  586. std::cerr << std::endl;
  587. #endif
  588. return olddir;
  589. }
  590. int FileIndex::removeOldDirectory(const std::string& fpath, const std::string& name, time_t old)
  591. {
  592. /* path is to parent */
  593. #ifdef FI_DEBUG_ALL
  594. std::cerr << "FileIndex::removeOldDirectory() Path: \"";
  595. std::cerr << fpath << "\"" << " + \"" << name << "\"";
  596. std::cerr << std::endl;
  597. #endif
  598. /* because of this find - we cannot get a child of
  599. * root (which is what we want!)
  600. */
  601. DirEntry *parent = root->findDirectory(fpath);
  602. /* for root directory case ... no subdir. */
  603. if (fpath == "")
  604. {
  605. #ifdef FI_DEBUG
  606. std::cerr << "FileIndex::removeOldDirectory() removing a root dir";
  607. std::cerr << std::endl;
  608. #endif
  609. parent = root;
  610. }
  611. if (!parent) {
  612. #ifdef FI_DEBUG
  613. std::cerr << "FileIndex::removeOldDirectory() NULL parent";
  614. std::cerr << std::endl;
  615. #endif
  616. return 0;
  617. }
  618. return parent -> removeOldDir(name, old);
  619. }
  620. int FileIndex::cleanOldEntries(time_t old) /* removes entries older than old */
  621. {
  622. int count = 0;
  623. std::map<std::string, DirEntry *>::iterator it;
  624. for(it = root->subdirs.begin(); it != root->subdirs.end(); ++it)
  625. {
  626. count += (it->second)->removeOldEntries(old, true);
  627. }
  628. return count;
  629. }
  630. int FileIndex::printFileIndex(std::ostream &out)
  631. {
  632. std::string sout ;
  633. printFileIndex(sout) ;
  634. out << sout << std::endl;
  635. return 1 ;
  636. }
  637. int FileIndex::printFileIndex(std::string &out)
  638. {
  639. out += "FileIndex::printFileIndex()\n";
  640. root->print(out);
  641. return 1;
  642. }
  643. int FileIndex::loadIndex(const std::string& filename, const RsFileHash& expectedHash, uint64_t size)
  644. {
  645. FILE *file = RsDirUtil::rs_fopen(filename.c_str(),"rb") ;
  646. if (!file)
  647. {
  648. #ifdef FI_DEBUG
  649. std::cerr << "FileIndex::loadIndex error opening file: " << filename;
  650. std::cerr << std::endl;
  651. #endif
  652. return 0;
  653. }
  654. std::string s ;
  655. {
  656. /* load file into memory, close file */
  657. RsTemporaryMemory compressed_data(size) ;
  658. if(!compressed_data)
  659. {
  660. std::cerr << "FileIndex::loadIndex(): can't allocate memory for " << size << " bytes." << std::endl;
  661. fclose(file);
  662. return 0;
  663. }
  664. uint64_t bytesread = 0 ;
  665. if(size != (bytesread = fread(compressed_data,1,size,file)))
  666. {
  667. std::cerr << "FileIndex::loadIndex(): can't read " << size << " bytes from file " << filename << ". Only " << bytesread << " actually read." << std::endl;
  668. fclose(file);
  669. return 0;
  670. }
  671. fclose(file);
  672. RsFileHash tmpout = RsDirUtil::sha1sum((unsigned char *)(compressed_data),size);
  673. // /* calculate hash */
  674. // unsigned char sha_buf[SHA_DIGEST_LENGTH];
  675. // SHA_CTX *sha_ctx = new SHA_CTX;
  676. // SHA1_Init(sha_ctx);
  677. // SHA1_Update(sha_ctx, s.c_str(), s.length());
  678. // SHA1_Final(&sha_buf[0], sha_ctx);
  679. // delete sha_ctx;
  680. //
  681. // std::string tmpout;
  682. // for(int i = 0; i < SHA_DIGEST_LENGTH; ++i)
  683. // {
  684. // rs_sprintf_append(tmpout, "%02x", (unsigned int) (sha_buf[i]));
  685. // }
  686. if (!expectedHash.isNull() && expectedHash != tmpout)
  687. {
  688. #ifdef FI_DEBUG
  689. std::cerr << "FileIndex::loadIndex expected hash does not match" << std::endl;
  690. std::cerr << "Expected hash: " << expectedHash << std::endl;
  691. std::cerr << "Hash found: " << tmpout << std::endl;
  692. #endif
  693. return 0;
  694. }
  695. // now uncompress the string
  696. //
  697. uint8_t *uncompressed_data = NULL ;
  698. unsigned int uncompressed_data_size = 0 ;
  699. if(!RsCompress::uncompress_memory_chunk(compressed_data,size,uncompressed_data,uncompressed_data_size))
  700. {
  701. std::cerr << "FileIndex::loadIndex() Decompression failed! Fileindex can't be read." << std::endl;
  702. free(uncompressed_data);
  703. return 0 ;
  704. }
  705. s = std::string((char *)uncompressed_data,uncompressed_data_size) ;
  706. std::cerr << " file = " << filename << std::endl;
  707. std::cerr << " uncompressed size = " << uncompressed_data_size << std::endl;
  708. std::cerr << " compressed size = " << size << std::endl;
  709. std::cerr << " hash = " << tmpout << std::endl;
  710. free(uncompressed_data) ;
  711. }
  712. #define FIND_NEXT(s,start,end,c) end = s.find(c, start); if (end == std::string::npos) end = s.length();
  713. DirEntry *ndir = NULL;
  714. FileEntry *nfile = NULL;
  715. std::list<DirEntry *> dirlist;
  716. std::string word;
  717. char ch;
  718. std::string::size_type pos = 0;
  719. while (pos < s.length())
  720. {
  721. ch = s[pos];
  722. ++pos;
  723. if (ch == '-')
  724. {
  725. FIND_NEXT(s, pos, pos, '\n');
  726. ++pos;
  727. switch(dirlist.size())
  728. {
  729. /* parse error: out of directory */
  730. case 0:
  731. {
  732. #ifdef FI_DEBUG
  733. std::cerr << "loadIndex error parsing saved file: " << filename;
  734. std::cerr << " Ran out of dirs";
  735. std::cerr << std::endl;
  736. #endif
  737. goto error;
  738. }
  739. /* finished parse, last dir is root */
  740. case 1:
  741. {
  742. RsPeerId pid = root -> id;
  743. FileIndex::unregisterEntry((void*)root) ;
  744. delete root; /* to clean up old entries */
  745. root = new PersonEntry(pid);
  746. registerEntry((void*)root) ;
  747. /* shallow copy of all except id */
  748. ndir = dirlist.back();
  749. dirlist.pop_back(); /* empty list */
  750. (*root) = (*ndir);
  751. /* now cleanup (can't call standard delete) */
  752. ndir->subdirs.clear();
  753. ndir->files.clear();
  754. FileIndex::unregisterEntry((void*)ndir) ;
  755. delete ndir;
  756. ndir = NULL;
  757. /* must reset parent pointers now */
  758. std::map<std::string, DirEntry *>::iterator it;
  759. for(it = root->subdirs.begin();
  760. it != root->subdirs.end(); ++it)
  761. {
  762. (it->second)->parent = root;
  763. }
  764. break;
  765. }
  766. /* pop stack */
  767. default: dirlist.pop_back(); ndir = dirlist.back();
  768. }
  769. continue;
  770. }
  771. // Ignore comments
  772. else if (ch == '#')
  773. {
  774. FIND_NEXT(s, pos, pos, '\n');
  775. ++pos;
  776. }
  777. else {
  778. std::vector<std::string> tokens;
  779. /* parse line */
  780. std::string::size_type lineend;
  781. FIND_NEXT(s, pos, lineend, '\n');
  782. std::string line = s.substr(pos, lineend - pos);
  783. pos = lineend + 1;
  784. std::string::size_type start = 0;
  785. while (start < line.length())
  786. {
  787. std::string::size_type end;
  788. FIND_NEXT(line, start, end, FILE_CACHE_SEPARATOR_CHAR);
  789. tokens.push_back(line.substr(start, end - start));
  790. start = end + 1;
  791. }
  792. /* create new file and add it to last directory*/
  793. if (ch == 'f')
  794. {
  795. if (tokens.size() != 6)
  796. {
  797. #ifdef FI_DEBUG
  798. std::cerr << "loadIndex error parsing saved file: " << filename;
  799. std::cerr << " File token count wrong: " << tokens.size();
  800. std::cerr << std::endl;
  801. for(unsigned int i = 0; i < tokens.size(); ++i)
  802. {
  803. std::cerr << "\tToken[" << i << "]:" << tokens[i];
  804. std::cerr << std::endl;
  805. }
  806. #endif
  807. goto error;
  808. }
  809. nfile = new FileEntry();
  810. registerEntry((void*)nfile) ;
  811. nfile->name = tokens[0];
  812. nfile->hash = RsFileHash(tokens[1]);
  813. nfile->size = atoll(tokens[2].c_str());
  814. nfile->modtime = atoi(tokens[3].c_str());
  815. nfile->pop = atoi(tokens[4].c_str());
  816. nfile->updtime = atoi(tokens[5].c_str());
  817. nfile->parent = ndir;
  818. nfile->row = ndir->subdirs.size() + ndir->files.size();
  819. ndir->files[nfile->name] = nfile;
  820. }
  821. /* create new dir and add to stack */
  822. else if (ch == 'd')
  823. {
  824. if (tokens.size() != 6)
  825. {
  826. #ifdef FI_DEBUG
  827. std::cerr << "loadIndex error parsing saved file: " << filename;
  828. std::cerr << " Dir token count wrong: " << tokens.size();
  829. std::cerr << std::endl;
  830. #endif
  831. goto error;
  832. }
  833. ndir = new DirEntry();
  834. registerEntry((void*)ndir) ;
  835. ndir->name = tokens[0];
  836. ndir->path = tokens[1];
  837. ndir->size = atoi(tokens[2].c_str());
  838. ndir->modtime = atoi(tokens[3].c_str());
  839. ndir->pop = atoi(tokens[4].c_str());
  840. ndir->updtime = atoi(tokens[5].c_str());
  841. if (!dirlist.empty())
  842. {
  843. ndir->parent = (dirlist.back());
  844. ndir->row = dirlist.back()->subdirs.size();
  845. dirlist.back()->subdirs[ndir->name] = ndir;
  846. }
  847. dirlist.push_back(ndir);
  848. }
  849. }
  850. }
  851. updateHashIndex() ;
  852. return 1;
  853. /* parse error encountered */
  854. error:
  855. #ifdef FI_DEBUG
  856. std::cerr << "loadIndex error parsing saved file: " << filename;
  857. std::cerr << std::endl;
  858. #endif
  859. return 0;
  860. }
  861. int FileIndex::saveIndex(const std::string& filename, RsFileHash &fileHash, uint64_t &size,const std::set<std::string>& forbidden_dirs)
  862. {
  863. std::string filenametmp = filename + ".tmp" ;
  864. std::string s;
  865. size = 0 ;
  866. /* print version and header */
  867. s += "# FileIndex version 0.1\n";
  868. s += "# Dir: d name, path, parent, size, modtime, pop, updtime;\n";
  869. s += "# File: f name, hash, size, modtime, pop, updtime;\n";
  870. s += "#\n";
  871. /* begin recusion */
  872. root->writeDirInfo(s) ;
  873. std::map<std::string, DirEntry *>::iterator it;
  874. for(it = root->subdirs.begin(); it != root->subdirs.end(); ++it)
  875. {
  876. #ifdef FI_DEBUG
  877. std::cout << "writting root directory: name=" << it->second->name << ", path=" << it->second->path << std::endl ;
  878. #endif
  879. if(forbidden_dirs.find(it->second->name) != forbidden_dirs.end())
  880. {
  881. #ifdef FI_DEBUG
  882. std::cerr << " will be suppressed." << std::endl ;
  883. #endif
  884. }
  885. else
  886. {
  887. #ifdef FI_DEBUG
  888. std::cerr << " will be saved." << std::endl ;
  889. #endif
  890. (it->second)->saveEntry(s);
  891. }
  892. }
  893. root->writeFileInfo(s) ; // this should never do anything
  894. /* signal to pop directory from stack in loadIndex() */
  895. s += "-\n";
  896. // now compress the data.
  897. #ifdef FI_DEBUG
  898. std::cerr << "FileIndex::saveIndex(): compressign data." << std::endl;
  899. #endif
  900. uint8_t *compressed_data = NULL ;
  901. uint32_t compressed_data_size = 0 ;
  902. if(!RsCompress::compress_memory_chunk((unsigned char *)s.c_str(),s.length(),compressed_data,compressed_data_size))
  903. {
  904. std::cerr << "(EE) ERROR in file list compression ! file list can't be saved" << std::endl;
  905. free(compressed_data);
  906. return false ;
  907. }
  908. fileHash = RsDirUtil::sha1sum((unsigned char *)compressed_data,compressed_data_size);
  909. #ifdef FI_DEBUG
  910. std::cerr << " file = " << filename << std::endl;
  911. std::cerr << " old size = " << s.length() << std::endl;
  912. std::cerr << " new size = " << compressed_data_size << std::endl;
  913. std::cerr << " hash = " << fileHash << std::endl;
  914. #endif
  915. // /* calculate sha1 hash */
  916. // SHA_CTX *sha_ctx = new SHA_CTX;
  917. // SHA1_Init(sha_ctx);
  918. // SHA1_Update(sha_ctx, s.c_str(), s.length());
  919. // SHA1_Final(&sha_buf[0], sha_ctx);
  920. // delete sha_ctx;
  921. //
  922. // for(int i = 0; i < SHA_DIGEST_LENGTH; ++i)
  923. // {
  924. // rs_sprintf_append(fileHash, "%02x", (unsigned int) (sha_buf[i]));
  925. // }
  926. /* finally, save to file */
  927. FILE *file = RsDirUtil::rs_fopen(filenametmp.c_str(), "wb");
  928. if (file == NULL)
  929. {
  930. std::cerr << "FileIndex::saveIndex error opening file for writting: " << filename << ". Giving up." << std::endl;
  931. return 0;
  932. }
  933. uint32_t outwritten ;
  934. if(compressed_data_size != (outwritten=fwrite(compressed_data,1,compressed_data_size,file)))
  935. {
  936. std::cerr << "FileIndex::saveIndex error. File not entirely written. Only " << outwritten << " bytes wrote out of " << compressed_data_size << " check for disk full, or disk quotas." << std::endl;
  937. fclose(file);
  938. return 0;
  939. }
  940. fclose(file);
  941. free(compressed_data) ;
  942. // Use a temp file name so that the file is never half saved.
  943. //
  944. if(!RsDirUtil::renameFile(filenametmp,filename))
  945. return false ;
  946. /* get the size out */
  947. struct stat64 buf;
  948. if(-1 == stat64(filename.c_str(), &buf))
  949. {
  950. std::cerr << "Can't determine size of file " << filename << ": errno = " << errno << std::endl ;
  951. return false ;
  952. }
  953. size=buf.st_size;
  954. return true;
  955. }
  956. std::string FixName(const std::string& _in)
  957. {
  958. /* replace any , with _ */
  959. std::string in(_in) ;
  960. for(unsigned int i = 0; i < in.length(); ++i)
  961. {
  962. if (in[i] == FILE_CACHE_SEPARATOR_CHAR)
  963. {
  964. in[i] = '_';
  965. }
  966. }
  967. return in;
  968. }
  969. void DirEntry::writeDirInfo(std::string& s)
  970. {
  971. /* print node info */
  972. rs_sprintf_append(s, "d%s%c%s%c%lld%c%ld%c%d%c%ld%c\n",
  973. FixName(name).c_str(), FILE_CACHE_SEPARATOR_CHAR,
  974. FixName(path).c_str(), FILE_CACHE_SEPARATOR_CHAR,
  975. size, FILE_CACHE_SEPARATOR_CHAR,
  976. modtime, FILE_CACHE_SEPARATOR_CHAR,
  977. pop, FILE_CACHE_SEPARATOR_CHAR,
  978. updtime, FILE_CACHE_SEPARATOR_CHAR);
  979. }
  980. void DirEntry::writeFileInfo(std::string& s)
  981. {
  982. /* print file info */
  983. std::map<std::string, FileEntry *>::iterator fit;
  984. for(fit = files.begin(); fit != files.end(); ++fit)
  985. {
  986. rs_sprintf_append(s, "f%s%c%s%c%lld%c%ld%c%d%c%ld%c\n",
  987. FixName((fit->second)->name).c_str(), FILE_CACHE_SEPARATOR_CHAR,
  988. (fit->second)->hash.toStdString().c_str(), FILE_CACHE_SEPARATOR_CHAR,
  989. (fit->second)->size, FILE_CACHE_SEPARATOR_CHAR,
  990. (fit->second)->modtime, FILE_CACHE_SEPARATOR_CHAR,
  991. (fit->second)->pop, FILE_CACHE_SEPARATOR_CHAR,
  992. (fit->second)->updtime, FILE_CACHE_SEPARATOR_CHAR);
  993. }
  994. }
  995. /* recusive function for traversing the dir tree in preorder */
  996. int DirEntry::saveEntry(std::string &s)
  997. {
  998. writeDirInfo(s) ;
  999. std::map<std::string, DirEntry *>::iterator it;
  1000. for(it = subdirs.begin(); it != subdirs.end(); ++it)
  1001. {
  1002. (it->second)->saveEntry(s);
  1003. }
  1004. writeFileInfo(s) ;
  1005. /* signal to pop directory from stack in loadIndex() */
  1006. s += "-\n";
  1007. return 1;
  1008. }
  1009. int FileIndex::searchHash(const RsFileHash& hash, std::list<FileEntry *> &results) const
  1010. {
  1011. #ifdef FI_DEBUG
  1012. std::cerr << "FileIndex::searchHash(" << hash << ")";
  1013. std::cerr << std::endl;
  1014. #endif
  1015. std::map<RsFileHash,FileEntry*>::const_iterator it = _file_hashes.find(hash) ;
  1016. if(it!=_file_hashes.end() && isValid((void*)it->second))
  1017. results.push_back(it->second) ;
  1018. #ifdef OLD_CODE_PLZ_REMOVE
  1019. DirEntry *ndir = NULL;
  1020. std::list<DirEntry *> dirlist;
  1021. dirlist.push_back(root);
  1022. while(!dirlist.empty())
  1023. {
  1024. ndir = dirlist.back();
  1025. dirlist.pop_back();
  1026. /* add subdirs to stack */
  1027. std::map<std::string, DirEntry *>::iterator it;
  1028. for(it = ndir->subdirs.begin(); it != ndir->subdirs.end(); ++it)
  1029. {
  1030. dirlist.push_back(it->second);
  1031. }
  1032. std::map<std::string, FileEntry *>::iterator fit;
  1033. /* search in current dir */
  1034. for(fit = ndir->files.begin(); fit != ndir->files.end(); ++fit)
  1035. {
  1036. if (hash == (fit->second)->hash)
  1037. {
  1038. results.push_back(fit->second);
  1039. #ifdef FI_DEBUG
  1040. std::cerr << "FileIndex::searchHash(" << hash << ")";
  1041. std::cerr << " found: " << fit->second->name;
  1042. std::cerr << std::endl;
  1043. #endif
  1044. }
  1045. }
  1046. }
  1047. #endif
  1048. return 0;
  1049. }
  1050. int FileIndex::searchTerms(const std::list<std::string>& terms, std::list<FileEntry *> &results) const
  1051. {
  1052. DirEntry *ndir = NULL;
  1053. std::list<DirEntry *> dirlist;
  1054. dirlist.push_back(root);
  1055. /* iterators */
  1056. std::map<std::string, DirEntry *>::iterator it;
  1057. std::map<std::string, FileEntry *>::iterator fit;
  1058. std::list<std::string>::const_iterator iter;
  1059. while(!dirlist.empty())
  1060. {
  1061. ndir = dirlist.back();
  1062. dirlist.pop_back();
  1063. for(it = ndir->subdirs.begin(); it != ndir->subdirs.end(); ++it)
  1064. {
  1065. dirlist.push_back(it->second);
  1066. }
  1067. for (iter = terms.begin(); iter != terms.end(); ++iter) {
  1068. std::string::const_iterator it2;
  1069. const std::string &str1 = ndir->name;
  1070. const std::string &str2 = *iter;
  1071. it2 = std::search(str1.begin(), str1.end(), str2.begin(), str2.end(), CompareCharIC());
  1072. if (it2 != str1.end()) {
  1073. /* first search to see if its parent is in the results list */
  1074. bool addDir = true;
  1075. for (std::list<FileEntry *>::iterator rit(results.begin()); rit != results.end() && addDir; ++rit) {
  1076. DirEntry *de = dynamic_cast<DirEntry *>(*rit);
  1077. if (de && (de == root))
  1078. continue;
  1079. if (de && (de == ndir->parent))
  1080. addDir = false;
  1081. }
  1082. if (addDir) {
  1083. results.push_back((FileEntry *) ndir);
  1084. break;
  1085. }
  1086. }
  1087. }
  1088. for(fit = ndir->files.begin(); fit != ndir->files.end(); ++fit)
  1089. {
  1090. /* cycle through terms */
  1091. for(iter = terms.begin(); iter != terms.end(); ++iter)
  1092. {
  1093. /* always ignore case */
  1094. std::string::const_iterator it2 ;
  1095. const std::string &str1 = fit->second->name;
  1096. const std::string &str2 = (*iter);
  1097. it2 = std::search( str1.begin(), str1.end(),
  1098. str2.begin(), str2.end(), CompareCharIC() );
  1099. if (it2 != str1.end())
  1100. {
  1101. results.push_back(fit->second);
  1102. break;
  1103. }
  1104. /* original case specific term search ******
  1105. if (fit->second->name.find(*iter) != std::string::npos)
  1106. {
  1107. results.push_back(fit->second);
  1108. break;
  1109. }
  1110. ************/
  1111. }
  1112. }
  1113. } //while
  1114. return 0;
  1115. }
  1116. int FileIndex::searchBoolExp(Expression * exp, std::list<FileEntry *> &results) const
  1117. {
  1118. DirEntry *ndir = NULL;
  1119. std::list<DirEntry *> dirlist;
  1120. dirlist.push_back(root);
  1121. /* iterators */
  1122. std::map<std::string, DirEntry *>::iterator it;
  1123. std::map<std::string, FileEntry *>::iterator fit;
  1124. std::list<std::string>::const_iterator iter;
  1125. while(!dirlist.empty())
  1126. {
  1127. ndir = dirlist.back();
  1128. dirlist.pop_back();
  1129. for(it = ndir->subdirs.begin(); it != ndir->subdirs.end(); ++it)
  1130. {
  1131. dirlist.push_back(it->second);
  1132. }
  1133. for(fit = ndir->files.begin(); fit != ndir->files.end(); ++fit)
  1134. {
  1135. /*Evaluate the boolean expression and add it to the results if its true*/
  1136. bool ret = exp->eval(fit->second);
  1137. if (ret == true){
  1138. results.push_back(fit->second);
  1139. }
  1140. }
  1141. } //while
  1142. return 0;
  1143. }
  1144. uint32_t FileIndex::getType(void *ref)
  1145. {
  1146. if(ref == NULL)
  1147. return DIR_TYPE_ROOT ;
  1148. if(!isValid(ref))
  1149. return DIR_TYPE_ROOT ;
  1150. return static_cast<FileEntry*>(ref)->type() ;
  1151. }
  1152. bool FileIndex::extractData(const std::string& fpath,DirDetails& details) const
  1153. {
  1154. void *ref = findRef(fpath) ;
  1155. if(ref == NULL)
  1156. return false ;
  1157. return extractData(ref,details) ;
  1158. }
  1159. void *FileIndex::findRef(const std::string& fpath) const
  1160. {
  1161. DirEntry *parent = root->findDirectory(fpath);
  1162. std::cerr << "findRef() Called on " << fpath << std::endl;
  1163. if (!parent)
  1164. {
  1165. //#ifdef FI_DEBUG
  1166. std::cerr << "FileIndex::updateFileEntry() NULL parent";
  1167. std::cerr << std::endl;
  1168. //#endif
  1169. return NULL;
  1170. }
  1171. std::cerr << "Found parent directory: " << std::endl;
  1172. std::cerr << " parent.name = " << parent->name << std::endl;
  1173. std::cerr << " parent.path = " << parent->path << std::endl;
  1174. if(parent->path == fpath) // directory!
  1175. {
  1176. std::cerr << " fpath is a directory. Returning parent!" << std::endl;
  1177. return parent ;
  1178. }
  1179. else
  1180. {
  1181. std::cerr << " fpath is a file. Looking into parent directory..." << std::endl;
  1182. /* search in current dir */
  1183. for(std::map<std::string, FileEntry *>::iterator fit = parent->files.begin(); fit != parent->files.end(); ++fit)
  1184. {
  1185. std::cerr << " trying " << parent->path + "/" + fit->second->name << std::endl;
  1186. if(parent->path + "/" + fit->second->name == fpath)
  1187. {
  1188. std::cerr << " found !" << std::endl;
  1189. return fit->second ;
  1190. }
  1191. }
  1192. std::cerr << " (EE) not found !" << std::endl;
  1193. return NULL ;
  1194. }
  1195. }
  1196. bool FileIndex::extractData(void *ref,DirDetails& details)
  1197. {
  1198. if(!isValid(ref))
  1199. {
  1200. #ifdef FI_DEBUG
  1201. std::cerr << "FileIndex::extractData() asked for an invalid pointer " << (void*)ref << std::endl;
  1202. #endif
  1203. return false ;
  1204. }
  1205. FileEntry *file = static_cast<FileEntry *>(ref);
  1206. DirEntry *dir = (file->hash.isNull())?static_cast<DirEntry *>(file):NULL ; // This is a hack to avoid doing a dynamic_cast
  1207. details.children.clear() ;
  1208. time_t now = time(NULL) ;
  1209. if (dir!=NULL) /* has children --- fill */
  1210. {
  1211. #ifdef FI_DEBUG
  1212. std::cerr << "FileIndex::extractData() ref=dir" << std::endl;
  1213. #endif
  1214. /* extract all the entries */
  1215. for(std::map<std::string,DirEntry*>::const_iterator dit(dir->subdirs.begin()); dit != dir->subdirs.end(); ++dit)
  1216. {
  1217. DirEntry *dirEntry = dit->second;
  1218. DirStub stub;
  1219. stub.type = DIR_TYPE_DIR;
  1220. stub.name = dirEntry -> name;
  1221. stub.ref = dirEntry;
  1222. details.children.push_back(stub);
  1223. }
  1224. for(std::map<std::string,FileEntry*>::const_iterator fit(dir->files.begin()); fit != dir->files.end(); ++fit)
  1225. {
  1226. FileEntry *fileEntry = fit->second;
  1227. DirStub stub;
  1228. stub.type = DIR_TYPE_FILE;
  1229. stub.name = fileEntry -> name;
  1230. stub.ref = fileEntry;
  1231. details.children.push_back(stub);
  1232. }
  1233. if(dir->parent == NULL)
  1234. details.type = DIR_TYPE_PERSON ;
  1235. else
  1236. details.type = DIR_TYPE_DIR;
  1237. details.hash.clear() ;
  1238. details.count = dir->subdirs.size() + dir->files.size();
  1239. details.min_age = now - dir->most_recent_time ;
  1240. }
  1241. else
  1242. {
  1243. #ifdef FI_DEBUG
  1244. std::cerr << "FileIndexStore::extractData() ref=file" << std::endl;
  1245. #endif
  1246. details.type = DIR_TYPE_FILE;
  1247. details.count = file->size;
  1248. details.min_age = now - file->modtime ;
  1249. }
  1250. #ifdef FI_DEBUG
  1251. std::cerr << "FileIndexStore::extractData() name: " << file->name << std::endl;
  1252. #endif
  1253. details.ref = file;
  1254. details.hash = file->hash;
  1255. details.age = now - file->modtime;
  1256. details.flags.clear() ;
  1257. /* find parent pointer, and row */
  1258. details.parent = file->parent ;
  1259. details.prow = (file->parent==NULL)?0:file->parent->row ;
  1260. if(details.type == DIR_TYPE_DIR)
  1261. {
  1262. details.name = file->name;
  1263. details.path = dir->path;
  1264. }
  1265. else
  1266. {
  1267. details.name = file->name;
  1268. details.path = (file->parent==NULL)?"":file->parent->path;
  1269. }
  1270. /* find peer id */
  1271. FileEntry *f ;
  1272. for(f=file;f->parent!=NULL;f=f->parent) ;
  1273. details.id = static_cast<PersonEntry*>(f)->id; // The topmost parent is necessarily a personEntrY, so we can avoid a dynamic_cast.
  1274. #ifdef FI_DEBUG
  1275. assert(details.parent != details.ref) ;
  1276. std::cout << "details: ref=" << (void*)ref << ", prow=" << details.prow << ", parent=" << (void*)details.parent << ", children=" ;
  1277. for(std::list<DirStub>::iterator it(details.children.begin());it!=details.children.end();++it)
  1278. std::cout << " " << (void*)it->ref ;
  1279. std::cout << std::endl ;
  1280. #endif
  1281. return true;
  1282. }