PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/libretroshare/src/util/rsdir.cc

https://gitlab.com/g10h4ck/RetroShare
C++ | 1399 lines | 1016 code | 234 blank | 149 comment | 264 complexity | 93c52855896d47f78329a78d297ded09 MD5 | raw file
Possible License(s): 0BSD, GPL-2.0, AGPL-1.0
  1. /*
  2. * "$Id: rsdir.cc,v 1.1 2007-02-19 20:08:30 rmf24 Exp $"
  3. *
  4. * RetroShare C++ Interface.
  5. *
  6. * Copyright 2004-2007 by Robert Fernie.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Library General Public
  10. * License Version 2 as published by the Free Software Foundation.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Library General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  20. * USA.
  21. *
  22. * Please report all bugs and problems to "retroshare@lunamutt.com".
  23. *
  24. */
  25. // Includes for directory creation.
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <fcntl.h>
  29. #include <unistd.h>
  30. #include "util/rsdir.h"
  31. #include "util/rsstring.h"
  32. #include "util/rsrandom.h"
  33. #include "retroshare/rstypes.h"
  34. #include "rsthreads.h"
  35. #include <iostream>
  36. #include <algorithm>
  37. #include <stdio.h>
  38. #include <dirent.h>
  39. #include <openssl/sha.h>
  40. #include <iomanip>
  41. #include <sstream>
  42. #include <fstream>
  43. #include <stdexcept>
  44. #if defined(WIN32) || defined(__CYGWIN__)
  45. #include "util/rsstring.h"
  46. #include "wtypes.h"
  47. #include <winioctl.h>
  48. #else
  49. #include <errno.h>
  50. #endif
  51. /****
  52. * #define RSDIR_DEBUG 1
  53. ****/
  54. std::string RsDirUtil::getTopDir(const std::string& dir)
  55. {
  56. std::string top;
  57. /* find the subdir: [/][dir1.../]<top>[/]
  58. */
  59. int i,j;
  60. int len = dir.length();
  61. for(j = len - 1; (j > 0) && (dir[j] == '/'); j--) ;
  62. for(i = j; (i > 0) && (dir[i] != '/'); i--) ;
  63. if (dir[i] == '/')
  64. i++;
  65. for(; i <= j; i++)
  66. {
  67. top += dir[i];
  68. }
  69. return top;
  70. }
  71. const char *RsDirUtil::scanf_string_for_uint(int bytes)
  72. {
  73. const char *strgs[3] = { "%u","%lu","%llu" } ;
  74. //std::cerr << "RsDirUtil::scanf_string_for_uint(): returning for bytes=" << bytes << std::endl;
  75. if(sizeof(unsigned int) == bytes)
  76. return strgs[0] ;
  77. if(sizeof(long unsigned int) == bytes)
  78. return strgs[1] ;
  79. if(sizeof(long long unsigned int) == bytes)
  80. return strgs[2] ;
  81. std::cerr << "RsDirUtil::scanf_string_for_uint(): no corresponding scan string for "<< bytes << " bytes. This will probably cause inconsistencies." << std::endl;
  82. return strgs[0] ;
  83. }
  84. void RsDirUtil::removeTopDir(const std::string& dir, std::string& path)
  85. {
  86. path.clear();
  87. /* remove the subdir: [/][dir1.../]<top>[/]
  88. */
  89. int j = dir.find_last_not_of('/');
  90. int i = dir.rfind('/', j);
  91. /* remove any more slashes */
  92. if (i > 0)
  93. {
  94. i = dir.find_last_not_of('/', i);
  95. }
  96. if (i > 0)
  97. {
  98. path.assign(dir, 0, i + 1);
  99. }
  100. }
  101. std::string RsDirUtil::getRootDir(const std::string& dir)
  102. {
  103. std::string root;
  104. /* find the subdir: [/]root[/...]
  105. */
  106. int i,j;
  107. int len = dir.length();
  108. for(i = 0; (i < len) && (dir[i] == '/'); i++) ;
  109. for(j = i; (j < len) && (dir[j] != '/'); j++) ;
  110. if (i == j)
  111. return root; /* empty */
  112. for(; i < j; i++)
  113. {
  114. root += dir[i];
  115. }
  116. return root;
  117. }
  118. std::string RsDirUtil::removeRootDir(const std::string& path)
  119. {
  120. unsigned int i, j;
  121. unsigned int len = path.length();
  122. std::string output;
  123. /* chew leading '/'s */
  124. for(i = 0; (i < len) && (path[i] == '/'); i++) ;
  125. if (i == len)
  126. return output; /* empty string */
  127. for(j = i; (j < len) && (path[j] != '/'); j++) ; /* run to next '/' */
  128. for(; (j < len) && (path[j] == '/'); j++) ; /* chew leading '/'s */
  129. for(; j < len; j++)
  130. {
  131. output += path[j];
  132. }
  133. return output;
  134. }
  135. std::string RsDirUtil::removeRootDirs(const std::string& path, const std::string& root)
  136. {
  137. /* too tired */
  138. std::string notroot;
  139. unsigned int i = 0, j = 0;
  140. /* catch empty data */
  141. if ((root.length() < 1) || (path.length() < 1))
  142. return notroot;
  143. if ((path[0] == '/') && (root[0] != '/'))
  144. {
  145. i++;
  146. }
  147. for(; (i < path.length()) && (j < root.length()) && (path[i] == root[j]); i++, j++) ;
  148. /* should have consumed root. */
  149. if (j == root.length())
  150. {
  151. //std::cerr << "matched root!" << std::endl;
  152. }
  153. else
  154. {
  155. //std::cerr << "failed i: " << i << ", j: " << j << std::endl;
  156. //std::cerr << "root: " << root << " path: " << path << std::endl;
  157. return notroot;
  158. }
  159. if (path[i] == '/')
  160. {
  161. i++;
  162. }
  163. for(; i < path.length(); i++)
  164. {
  165. notroot += path[i];
  166. }
  167. //std::cerr << "Found NotRoot: " << notroot << std::endl;
  168. return notroot;
  169. }
  170. int RsDirUtil::breakupDirList(const std::string& path,
  171. std::list<std::string> &subdirs)
  172. {
  173. int start = 0;
  174. unsigned int i;
  175. for(i = 0; i < path.length(); i++)
  176. {
  177. if (path[i] == '/')
  178. {
  179. if (i - start > 0)
  180. {
  181. subdirs.push_back(path.substr(start, i-start));
  182. }
  183. start = i+1;
  184. }
  185. }
  186. // get the final one.
  187. if (i - start > 0)
  188. {
  189. subdirs.push_back(path.substr(start, i-start));
  190. }
  191. return 1;
  192. }
  193. /**** Copied and Tweaked from ftcontroller ***/
  194. bool RsDirUtil::fileExists(const std::string& filename)
  195. {
  196. return ( access( filename.c_str(), F_OK ) != -1 );
  197. }
  198. /**** Copied and Tweaked from ftcontroller ***/
  199. bool RsDirUtil::copyFile(const std::string& source,const std::string& dest)
  200. {
  201. #ifdef WINDOWS_SYS
  202. std::wstring sourceW;
  203. std::wstring destW;
  204. librs::util::ConvertUtf8ToUtf16(source,sourceW);
  205. librs::util::ConvertUtf8ToUtf16(dest,destW);
  206. return (CopyFileW(sourceW.c_str(), destW.c_str(), FALSE) != 0);
  207. #else
  208. FILE *in = fopen64(source.c_str(),"rb") ;
  209. if(in == NULL)
  210. {
  211. return false ;
  212. }
  213. FILE *out = fopen64(dest.c_str(),"wb") ;
  214. if(out == NULL)
  215. {
  216. fclose (in);
  217. return false ;
  218. }
  219. size_t s=0;
  220. size_t T=0;
  221. static const int BUFF_SIZE = 10485760 ; // 10 MB buffer to speed things up.
  222. void *buffer = malloc(BUFF_SIZE) ;
  223. bool bRet = true;
  224. while( (s = fread(buffer,1,BUFF_SIZE,in)) > 0)
  225. {
  226. size_t t = fwrite(buffer,1,s,out) ;
  227. T += t ;
  228. if(t != s)
  229. {
  230. bRet = false ;
  231. break;
  232. }
  233. }
  234. fclose(in) ;
  235. fclose(out) ;
  236. free(buffer) ;
  237. return true ;
  238. #endif
  239. }
  240. bool RsDirUtil::checkFile(const std::string& filename,uint64_t& file_size,bool disallow_empty_file)
  241. {
  242. int val;
  243. mode_t st_mode;
  244. #ifdef WINDOWS_SYS
  245. std::wstring wfilename;
  246. librs::util::ConvertUtf8ToUtf16(filename, wfilename);
  247. struct _stat buf;
  248. val = _wstat(wfilename.c_str(), &buf);
  249. st_mode = buf.st_mode;
  250. #else
  251. struct stat64 buf;
  252. val = stat64(filename.c_str(), &buf);
  253. st_mode = buf.st_mode;
  254. #endif
  255. if (val == -1)
  256. {
  257. #ifdef RSDIR_DEBUG
  258. std::cerr << "RsDirUtil::checkFile() ";
  259. std::cerr << filename << " doesn't exist" << std::endl;
  260. #endif
  261. return false;
  262. }
  263. else if (!S_ISREG(st_mode))
  264. {
  265. // Some other type - error.
  266. #ifdef RSDIR_DEBUG
  267. std::cerr << "RsDirUtil::checkFile() ";
  268. std::cerr << filename << " is not a Regular File" << std::endl;
  269. #endif
  270. return false;
  271. }
  272. file_size = buf.st_size ;
  273. if(disallow_empty_file && buf.st_size == 0)
  274. return false ;
  275. return true;
  276. }
  277. bool RsDirUtil::checkDirectory(const std::string& dir)
  278. {
  279. int val;
  280. mode_t st_mode;
  281. #ifdef WINDOWS_SYS
  282. std::wstring wdir;
  283. librs::util::ConvertUtf8ToUtf16(dir, wdir);
  284. struct _stat buf;
  285. val = _wstat(wdir.c_str(), &buf);
  286. st_mode = buf.st_mode;
  287. #else
  288. struct stat buf;
  289. val = stat(dir.c_str(), &buf);
  290. st_mode = buf.st_mode;
  291. #endif
  292. if (val == -1)
  293. {
  294. #ifdef RSDIR_DEBUG
  295. std::cerr << "RsDirUtil::checkDirectory() ";
  296. std::cerr << dir << " doesn't exist" << std::endl;
  297. #endif
  298. return false;
  299. }
  300. else if (!S_ISDIR(st_mode))
  301. {
  302. // Some other type - error.
  303. #ifdef RSDIR_DEBUG
  304. std::cerr << "RsDirUtil::checkDirectory() ";
  305. std::cerr << dir << " is not Directory" << std::endl;
  306. #endif
  307. return false;
  308. }
  309. return true;
  310. }
  311. bool RsDirUtil::checkCreateDirectory(const std::string& dir)
  312. {
  313. #ifdef RSDIR_DEBUG
  314. std::cerr << "RsDirUtil::checkCreateDirectory() dir: " << dir << std::endl;
  315. #endif
  316. #ifdef WINDOWS_SYS
  317. std::wstring wdir;
  318. librs::util::ConvertUtf8ToUtf16(dir, wdir);
  319. _WDIR *direc = _wopendir(wdir.c_str());
  320. if (!direc)
  321. #else
  322. DIR *direc = opendir(dir.c_str());
  323. if (!direc)
  324. #endif
  325. {
  326. // directory don't exist. create.
  327. /******************************** WINDOWS/UNIX SPECIFIC PART ******************/
  328. #ifndef WINDOWS_SYS // UNIX
  329. if (-1 == mkdir(dir.c_str(), 0777))
  330. #else // WIN
  331. if (-1 == _wmkdir(wdir.c_str()))
  332. #endif
  333. /******************************** WINDOWS/UNIX SPECIFIC PART ******************/
  334. {
  335. #ifdef RSDIR_DEBUG
  336. std::cerr << "check_create_directory() Fatal Error et oui--";
  337. std::cerr <<std::endl<< "\tcannot create:" <<dir<<std::endl;
  338. #endif
  339. return 0;
  340. }
  341. #ifdef RSDIR_DEBUG
  342. std::cerr << "check_create_directory()";
  343. std::cerr <<std::endl<< "\tcreated:" <<dir<<std::endl;
  344. #endif
  345. return 1;
  346. }
  347. #ifdef RSDIR_DEBUG
  348. std::cerr << "check_create_directory()";
  349. std::cerr <<std::endl<< "\tDir Exists:" <<dir<<std::endl;
  350. #endif
  351. #ifdef WINDOWS_SYS
  352. _wclosedir(direc);
  353. #else
  354. closedir(direc) ;
  355. #endif
  356. return 1;
  357. }
  358. bool RsDirUtil::cleanupDirectory(const std::string& cleandir, const std::set<std::string> &keepFiles)
  359. {
  360. /* check for the dir existance */
  361. #ifdef WINDOWS_SYS
  362. std::wstring wcleandir;
  363. librs::util::ConvertUtf8ToUtf16(cleandir, wcleandir);
  364. _WDIR *dir = _wopendir(wcleandir.c_str());
  365. #else
  366. DIR *dir = opendir(cleandir.c_str());
  367. #endif
  368. if (!dir)
  369. {
  370. return false;
  371. }
  372. #ifdef WINDOWS_SYS
  373. struct _wdirent *dent;
  374. struct _stat buf;
  375. while(NULL != (dent = _wreaddir(dir)))
  376. #else
  377. struct dirent *dent;
  378. struct stat buf;
  379. while(NULL != (dent = readdir(dir)))
  380. #endif
  381. {
  382. /* check entry type */
  383. #ifdef WINDOWS_SYS
  384. const std::wstring &wfname = dent -> d_name;
  385. std::wstring wfullname = wcleandir + L"/" + wfname;
  386. #else
  387. const std::string &fname = dent -> d_name;
  388. std::string fullname = cleandir + "/" + fname;
  389. #endif
  390. #ifdef WINDOWS_SYS
  391. if (-1 != _wstat(wfullname.c_str(), &buf))
  392. #else
  393. if (-1 != stat(fullname.c_str(), &buf))
  394. #endif
  395. {
  396. /* only worry about files */
  397. if (S_ISREG(buf.st_mode))
  398. {
  399. #ifdef WINDOWS_SYS
  400. std::string fname;
  401. librs::util::ConvertUtf16ToUtf8(wfname, fname);
  402. #endif
  403. /* check if we should keep it */
  404. if (keepFiles.end() == std::find(keepFiles.begin(), keepFiles.end(), fname))
  405. {
  406. /* can remove */
  407. #ifdef WINDOWS_SYS
  408. _wremove(wfullname.c_str());
  409. #else
  410. remove(fullname.c_str());
  411. #endif
  412. }
  413. }
  414. }
  415. }
  416. /* close directory */
  417. #ifdef WINDOWS_SYS
  418. _wclosedir(dir);
  419. #else
  420. closedir(dir);
  421. #endif
  422. return true;
  423. }
  424. /* faster cleanup - first construct two sets - then iterate over together */
  425. bool RsDirUtil::cleanupDirectoryFaster(const std::string& cleandir, const std::set<std::string> &keepFiles)
  426. {
  427. /* check for the dir existance */
  428. #ifdef WINDOWS_SYS
  429. std::map<std::string, std::wstring> fileMap;
  430. std::map<std::string, std::wstring>::const_iterator fit;
  431. std::wstring wcleandir;
  432. librs::util::ConvertUtf8ToUtf16(cleandir, wcleandir);
  433. _WDIR *dir = _wopendir(wcleandir.c_str());
  434. #else
  435. std::map<std::string, std::string> fileMap;
  436. std::map<std::string, std::string>::const_iterator fit;
  437. DIR *dir = opendir(cleandir.c_str());
  438. #endif
  439. if (!dir)
  440. {
  441. return false;
  442. }
  443. #ifdef WINDOWS_SYS
  444. struct _wdirent *dent;
  445. struct _stat buf;
  446. while(NULL != (dent = _wreaddir(dir)))
  447. {
  448. const std::wstring &wfname = dent -> d_name;
  449. std::wstring wfullname = wcleandir + L"/" + wfname;
  450. if (-1 != _wstat(wfullname.c_str(), &buf))
  451. {
  452. /* only worry about files */
  453. if (S_ISREG(buf.st_mode))
  454. {
  455. std::string fname;
  456. librs::util::ConvertUtf16ToUtf8(wfname, fname);
  457. fileMap[fname] = wfullname;
  458. }
  459. }
  460. }
  461. #else
  462. struct dirent *dent;
  463. struct stat buf;
  464. while(NULL != (dent = readdir(dir)))
  465. {
  466. const std::string &fname = dent -> d_name;
  467. std::string fullname = cleandir + "/" + fname;
  468. if (-1 != stat(fullname.c_str(), &buf))
  469. {
  470. /* only worry about files */
  471. if (S_ISREG(buf.st_mode))
  472. {
  473. fileMap[fname] = fullname;
  474. }
  475. }
  476. }
  477. #endif
  478. std::set<std::string>::const_iterator kit;
  479. fit = fileMap.begin();
  480. kit = keepFiles.begin();
  481. while(fit != fileMap.end() && kit != keepFiles.end())
  482. {
  483. if (fit->first < *kit) // fit is not in keep list;
  484. {
  485. #ifdef WINDOWS_SYS
  486. _wremove(fit->second.c_str());
  487. #else
  488. remove(fit->second.c_str());
  489. #endif
  490. ++fit;
  491. }
  492. else if (*kit < fit->first) // keepitem doesn't exist.
  493. {
  494. ++kit;
  495. }
  496. else // in keep list.
  497. {
  498. ++fit;
  499. ++kit;
  500. }
  501. }
  502. // cleanup extra that aren't in keep list.
  503. while(fit != fileMap.end())
  504. {
  505. #ifdef WINDOWS_SYS
  506. _wremove(fit->second.c_str());
  507. #else
  508. remove(fit->second.c_str());
  509. #endif
  510. ++fit;
  511. }
  512. /* close directory */
  513. #ifdef WINDOWS_SYS
  514. _wclosedir(dir);
  515. #else
  516. closedir(dir);
  517. #endif
  518. return true;
  519. }
  520. /* slightly nicer helper function */
  521. bool RsDirUtil::hashFile(const std::string& filepath,
  522. std::string &name, RsFileHash &hash, uint64_t &size)
  523. {
  524. if (getFileHash(filepath, hash, size))
  525. {
  526. /* extract file name */
  527. name = RsDirUtil::getTopDir(filepath);
  528. return true;
  529. }
  530. return false;
  531. }
  532. #include <openssl/sha.h>
  533. #include <iomanip>
  534. /* Function to hash, and get details of a file */
  535. bool RsDirUtil::getFileHash(const std::string& filepath, RsFileHash &hash, uint64_t &size, RsThread *thread /*= NULL*/)
  536. {
  537. FILE *fd;
  538. if (NULL == (fd = RsDirUtil::rs_fopen(filepath.c_str(), "rb")))
  539. return false;
  540. int len;
  541. SHA_CTX *sha_ctx = new SHA_CTX;
  542. unsigned char sha_buf[SHA_DIGEST_LENGTH];
  543. unsigned char gblBuf[512];
  544. /* determine size */
  545. fseeko64(fd, 0, SEEK_END);
  546. size = ftello64(fd);
  547. fseeko64(fd, 0, SEEK_SET);
  548. /* check if thread is running */
  549. bool isRunning = thread ? thread->isRunning() : true;
  550. int runningCheckCount = 0;
  551. SHA1_Init(sha_ctx);
  552. while(isRunning && (len = fread(gblBuf,1, 512, fd)) > 0)
  553. {
  554. SHA1_Update(sha_ctx, gblBuf, len);
  555. if (thread && ++runningCheckCount > (10 * 1024)) {
  556. /* check all 50MB if thread is running */
  557. isRunning = thread->isRunning();
  558. runningCheckCount = 0;
  559. }
  560. }
  561. /* Thread has ended */
  562. if (isRunning == false)
  563. {
  564. delete sha_ctx;
  565. fclose(fd);
  566. return false;
  567. }
  568. /* reading failed for some reason */
  569. if (ferror(fd))
  570. {
  571. delete sha_ctx;
  572. fclose(fd);
  573. return false;
  574. }
  575. SHA1_Final(&sha_buf[0], sha_ctx);
  576. hash = Sha1CheckSum(sha_buf);
  577. delete sha_ctx;
  578. fclose(fd);
  579. return true;
  580. }
  581. /* Function to hash, and get details of a file */
  582. Sha1CheckSum RsDirUtil::sha1sum(const unsigned char *data, uint32_t size)
  583. {
  584. SHA_CTX sha_ctx ;
  585. if(SHA_DIGEST_LENGTH != 20)
  586. throw std::runtime_error("Warning: can't compute Sha1Sum with sum size != 20") ;
  587. SHA1_Init(&sha_ctx);
  588. while(size > 512)
  589. {
  590. SHA1_Update(&sha_ctx, data, 512);
  591. data = &data[512] ;
  592. size -= 512 ;
  593. }
  594. SHA1_Update(&sha_ctx, data, size);
  595. unsigned char sha_buf[SHA_DIGEST_LENGTH];
  596. SHA1_Final(&sha_buf[0], &sha_ctx);
  597. return Sha1CheckSum(sha_buf) ;
  598. }
  599. bool RsDirUtil::saveStringToFile(const std::string &file, const std::string &str)
  600. {
  601. std::ofstream out(file.c_str(), std::ios_base::out | std::ios_base::binary);
  602. if(!out.is_open())
  603. {
  604. std::cerr << "RsDirUtil::saveStringToFile() ERROR: can't open file " << file << std::endl;
  605. return false;
  606. }
  607. out << str;
  608. return true;
  609. }
  610. bool RsDirUtil::loadStringFromFile(const std::string &file, std::string &str)
  611. {
  612. std::ifstream in(file.c_str(), std::ios_base::in | std::ios_base::binary);
  613. if(!in.is_open())
  614. {
  615. std::cerr << "RsDirUtil::loadStringFromFile() ERROR: can't open file " << file << std::endl;
  616. return false;
  617. }
  618. std::stringstream buffer;
  619. buffer << in.rdbuf();
  620. str = buffer.str();
  621. return true;
  622. }
  623. bool RsDirUtil::renameFile(const std::string& from, const std::string& to)
  624. {
  625. int loops = 0;
  626. #ifdef WINDOWS_SYS
  627. std::wstring f;
  628. librs::util::ConvertUtf8ToUtf16(from, f);
  629. std::wstring t;
  630. librs::util::ConvertUtf8ToUtf16(to, t);
  631. while (!MoveFileEx(f.c_str(), t.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))
  632. #else
  633. std::string f(from),t(to) ;
  634. while (rename(from.c_str(), to.c_str()) < 0)
  635. #endif
  636. {
  637. #ifdef WIN32
  638. if (GetLastError() != ERROR_ACCESS_DENIED)
  639. #else
  640. if (errno != EACCES)
  641. #endif
  642. /* set errno? */
  643. return false ;
  644. usleep(100 * 1000); // 100 msec
  645. if (loops >= 30)
  646. return false ;
  647. loops++;
  648. }
  649. return true ;
  650. }
  651. #ifdef UNUSED_CODE
  652. // not used
  653. bool RsDirUtil::createBackup (const std::string& sFilename, unsigned int nCount)
  654. {
  655. #ifdef WINDOWS_SYS
  656. if (GetFileAttributesA (sFilename.c_str ()) == -1) {
  657. // file doesn't exist
  658. return true;
  659. }
  660. // search last backup
  661. int nLast;
  662. for (nLast = nCount; nLast >= 1; nLast--) {
  663. std::ostringstream sStream; // please do not use std::ostringstream
  664. sStream << sFilename << nLast << ".bak";
  665. if (GetFileAttributesA (sStream.str ().c_str ()) != -1) {
  666. break;
  667. }
  668. }
  669. // delete max backup
  670. if (nLast == nCount) {
  671. std::ostringstream sStream; // please do not use std::ostringstream
  672. sStream << sFilename << nCount << ".bak";
  673. if (DeleteFileA (sStream.str ().c_str ()) == FALSE) {
  674. getPqiNotify()->AddSysMessage (0, RS_SYS_WARNING, "File delete error", "Error while deleting file " + sStream.str ());
  675. return false;
  676. }
  677. nLast--;
  678. }
  679. // rename backups
  680. for (int nIndex = nLast; nIndex >= 1; nIndex--) {
  681. std::ostringstream sStream; // please do not use std::ostringstream
  682. sStream << sFilename << nIndex << ".bak";
  683. std::ostringstream sStream1; // please do not use std::ostringstream
  684. sStream1 << sFilename << nIndex + 1 << ".bak";
  685. if (renameFile (sStream.str (), sStream1.str ()) == false) {
  686. getPqiNotify()->AddSysMessage (0, RS_SYS_WARNING, "File rename error", "Error while renaming file " + sStream.str () + " to " + sStream1.str ());
  687. return false;
  688. }
  689. }
  690. // copy backup
  691. std::ostringstream sStream; // please do not use std::ostringstream
  692. sStream << sFilename << 1 << ".bak";
  693. if (CopyFileA (sFilename.c_str (), sStream.str ().c_str (), FALSE) == FALSE) {
  694. getPqiNotify()->AddSysMessage (0, RS_SYS_WARNING, "File rename error", "Error while renaming file " + sFilename + " to " + sStream.str ());
  695. return false;
  696. }
  697. #else
  698. /* remove unused parameter warnings */
  699. (void) sFilename;
  700. (void) nCount;
  701. #endif
  702. return true;
  703. }
  704. #endif
  705. FILE *RsDirUtil::rs_fopen(const char* filename, const char* mode)
  706. {
  707. #ifdef WINDOWS_SYS
  708. std::wstring wfilename;
  709. librs::util::ConvertUtf8ToUtf16(filename, wfilename);
  710. std::wstring wmode;
  711. librs::util::ConvertUtf8ToUtf16(mode, wmode);
  712. return _wfopen(wfilename.c_str(), wmode.c_str());
  713. #else
  714. return fopen64(filename, mode);
  715. #endif
  716. }
  717. std::string RsDirUtil::convertPathToUnix(std::string path)
  718. {
  719. for (unsigned int i = 0; i < path.length(); i++)
  720. {
  721. if (path[i] == '\\')
  722. path[i] = '/';
  723. }
  724. return path;
  725. }
  726. std::string RsDirUtil::makePath(const std::string &path1, const std::string &path2)
  727. {
  728. std::string path = path1;
  729. if (path.empty() == false && *path.rbegin() != '/') {
  730. path += "/";
  731. }
  732. path += path2;
  733. return path;
  734. }
  735. int RsDirUtil::createLockFile(const std::string& lock_file_path, rs_lock_handle_t &lock_handle)
  736. {
  737. /******************************** WINDOWS/UNIX SPECIFIC PART ******************/
  738. #ifndef WINDOWS_SYS
  739. // Suspended. The user should make sure he's not already using the file descriptor.
  740. // if(lock_handle != -1)
  741. // close(lock_handle);
  742. // open the file in write mode, create it if necessary, truncate it (it should be empty)
  743. lock_handle = open(lock_file_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  744. if(lock_handle == -1)
  745. {
  746. std::cerr << "Could not open lock file " << lock_file_path.c_str() << std::flush;
  747. perror(NULL);
  748. return 2;
  749. }
  750. // see "man fcntl" for the details, in short: non blocking lock creation on the whole file contents
  751. struct flock lockDetails;
  752. lockDetails.l_type = F_WRLCK;
  753. lockDetails.l_whence = SEEK_SET;
  754. lockDetails.l_start = 0;
  755. lockDetails.l_len = 0;
  756. if(fcntl(lock_handle, F_SETLK, &lockDetails) == -1)
  757. {
  758. int fcntlErr = errno;
  759. std::cerr << "Could not request lock on file " << lock_file_path.c_str() << std::flush;
  760. perror(NULL);
  761. // there's no lock so let's release the file handle immediately
  762. close(lock_handle);
  763. lock_handle = -1;
  764. if(fcntlErr == EACCES || fcntlErr == EAGAIN)
  765. return 1;
  766. else
  767. return 2;
  768. }
  769. return 0;
  770. #else
  771. // Suspended. The user should make sure he's not already using the file descriptor.
  772. //
  773. // if (lock_handle) {
  774. // CloseHandle(lock_handle);
  775. // }
  776. std::wstring wlockFile;
  777. librs::util::ConvertUtf8ToUtf16(lock_file_path, wlockFile);
  778. // open the file in write mode, create it if necessary
  779. lock_handle = CreateFile(wlockFile.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
  780. if (lock_handle == INVALID_HANDLE_VALUE)
  781. {
  782. DWORD lasterror = GetLastError();
  783. std::cerr << "Could not open lock file " << lock_file_path.c_str() << std::endl;
  784. std::cerr << "Last error: " << lasterror << std::endl << std::flush;
  785. perror(NULL);
  786. if (lasterror == ERROR_SHARING_VIOLATION || lasterror == ERROR_ACCESS_DENIED)
  787. return 1;
  788. return 2;
  789. }
  790. return 0;
  791. #endif
  792. /******************************** WINDOWS/UNIX SPECIFIC PART ******************/
  793. }
  794. void RsDirUtil::releaseLockFile(rs_lock_handle_t lockHandle)
  795. {
  796. /******************************** WINDOWS/UNIX SPECIFIC PART ******************/
  797. #ifndef WINDOWS_SYS
  798. if(lockHandle != -1)
  799. {
  800. close(lockHandle);
  801. lockHandle = -1;
  802. }
  803. #else
  804. if(lockHandle)
  805. {
  806. CloseHandle(lockHandle);
  807. lockHandle = 0;
  808. }
  809. #endif
  810. /******************************** WINDOWS/UNIX SPECIFIC PART ******************/
  811. }
  812. RsStackFileLock::RsStackFileLock(const std::string& file_path)
  813. {
  814. while(RsDirUtil::createLockFile(file_path,_file_handle))
  815. {
  816. std::cerr << "Cannot acquire file lock " << file_path << ", waiting 1 sec." << std::endl;
  817. usleep(1 * 1000 * 1000) ; // 1 sec
  818. }
  819. #ifdef RSDIR_DEBUG
  820. std::cerr << "Acquired file handle " << _file_handle << ", lock file:" << file_path << std::endl;
  821. #endif
  822. }
  823. RsStackFileLock::~RsStackFileLock()
  824. {
  825. RsDirUtil::releaseLockFile(_file_handle) ;
  826. #ifdef RSDIR_DEBUG
  827. std::cerr << "Released file lock with handle " << _file_handle << std::endl;
  828. #endif
  829. }
  830. #if 0 // NOT ENABLED YET!
  831. /************************* WIDE STRING ***************************/
  832. /************************* WIDE STRING ***************************/
  833. /************************* WIDE STRING ***************************/
  834. std::wstring RsDirUtil::getWideTopDir(std::wstring dir)
  835. {
  836. std::wstring top;
  837. /* find the subdir: [/][dir1.../]<top>[/]
  838. */
  839. int i,j;
  840. int len = dir.length();
  841. for(j = len - 1; (j > 0) && (dir[j] == '/'); j--);
  842. for(i = j; (i > 0) && (dir[i] != '/'); i--);
  843. if (dir[i] == '/')
  844. i++;
  845. for(; i <= j; i++)
  846. {
  847. top += dir[i];
  848. }
  849. return top;
  850. }
  851. std::wstring RsDirUtil::removeWideTopDir(std::wstring dir)
  852. {
  853. std::wstring rest;
  854. /* remove the subdir: [/][dir1.../]<top>[/]
  855. */
  856. int i,j;
  857. int len = dir.length();
  858. for(j = len - 1; (j > 0) && (dir[j] == '/'); j--);
  859. for(i = j; (i >= 0) && (dir[i] != '/'); i--);
  860. /* remove any more slashes */
  861. for(; (i >= 0) && (dir[i] == '/'); i--);
  862. for(j = 0; j <= i; j++)
  863. {
  864. rest += dir[j];
  865. }
  866. return rest;
  867. }
  868. std::wstring RsDirUtil::getWideRootDir(std::wstring dir)
  869. {
  870. std::wstring root;
  871. /* find the subdir: [/]root[/...]
  872. */
  873. int i,j;
  874. int len = dir.length();
  875. for(i = 0; (i < len) && (dir[i] == '/'); i++);
  876. for(j = i; (j < len) && (dir[j] != '/'); j++);
  877. if (i == j)
  878. return root; /* empty */
  879. for(; i < j; i++)
  880. {
  881. root += dir[i];
  882. }
  883. return root;
  884. }
  885. std::wstring RsDirUtil::removeWideRootDir(std::wstring path)
  886. {
  887. unsigned int i, j;
  888. unsigned int len = path.length();
  889. std::wstring output;
  890. /* chew leading '/'s */
  891. for(i = 0; (i < len) && (path[i] == '/'); i++);
  892. if (i == len)
  893. return output; /* empty string */
  894. for(j = i; (j < len) && (path[j] != '/'); j++); /* run to next '/' */
  895. for(; (j < len) && (path[j] == '/'); j++); /* chew leading '/'s */
  896. for(; j < len; j++)
  897. {
  898. output += path[j];
  899. }
  900. return output;
  901. }
  902. std::wstring RsDirUtil::removeWideRootDirs(std::wstring path, std::wstring root)
  903. {
  904. /* too tired */
  905. std::wstring notroot;
  906. unsigned int i = 0, j = 0;
  907. /* catch empty data */
  908. if ((root.length() < 1) || (path.length() < 1))
  909. return notroot;
  910. if ((path[0] == '/') && (root[0] != '/'))
  911. {
  912. i++;
  913. }
  914. for(; (i < path.length()) && (j < root.length()) && (path[i] == root[j]); i++, j++);
  915. /* should have consumed root. */
  916. if (j == root.length())
  917. {
  918. //std::cerr << "matched root!" << std::endl;
  919. }
  920. else
  921. {
  922. //std::cerr << "failed i: " << i << ", j: " << j << std::endl;
  923. //std::cerr << "root: " << root << " path: " << path << std::endl;
  924. return notroot;
  925. }
  926. if (path[i] == '/')
  927. {
  928. i++;
  929. }
  930. for(; i < path.length(); i++)
  931. {
  932. notroot += path[i];
  933. }
  934. //std::cerr << "Found NotRoot: " << notroot << std::endl;
  935. return notroot;
  936. }
  937. int RsDirUtil::breakupWideDirList(std::wstring path,
  938. std::list<std::wstring> &subdirs)
  939. {
  940. int start = 0;
  941. unsigned int i;
  942. for(i = 0; i < path.length(); i++)
  943. {
  944. if (path[i] == '/')
  945. {
  946. if (i - start > 0)
  947. {
  948. subdirs.push_back(path.substr(start, i-start));
  949. }
  950. start = i+1;
  951. }
  952. }
  953. // get the final one.
  954. if (i - start > 0)
  955. {
  956. subdirs.push_back(path.substr(start, i-start));
  957. }
  958. return 1;
  959. }
  960. bool RsDirUtil::checkWideDirectory(std::wstring dir)
  961. {
  962. struct stat buf;
  963. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  964. std::string d(dir.begin(), dir.end());
  965. int val = stat(d.c_str(), &buf);
  966. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  967. if (val == -1)
  968. {
  969. #ifdef RSDIR_DEBUG
  970. std::cerr << "RsDirUtil::checkDirectory() ";
  971. std::cerr << d << " doesn't exist" << std::endl;
  972. #endif
  973. return false;
  974. }
  975. else if (!S_ISDIR(buf.st_mode))
  976. {
  977. // Some other type - error.
  978. #ifdef RSDIR_DEBUG
  979. std::cerr << "RsDirUtil::checkDirectory() ";
  980. std::cerr << d << " is not Directory" << std::endl;
  981. #endif
  982. return false;
  983. }
  984. return true;
  985. }
  986. bool RsDirUtil::checkWideCreateDirectory(std::wstring dir)
  987. {
  988. struct stat buf;
  989. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  990. std::string d(dir.begin(), dir.end());
  991. int val = stat(d.c_str(), &buf);
  992. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  993. if (val == -1)
  994. {
  995. // directory don't exist. create.
  996. /******************************** WINDOWS/UNIX SPECIFIC PART ******************/
  997. #ifndef WINDOWS_SYS // UNIX
  998. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  999. if (-1 == mkdir(d.c_str(), 0777))
  1000. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1001. #else // WIN
  1002. if (-1 == mkdir(d.c_str()))
  1003. #endif
  1004. /******************************** WINDOWS/UNIX SPECIFIC PART ******************/
  1005. {
  1006. #ifdef RSDIR_DEBUG
  1007. std::cerr << "check_create_directory() Fatal Error --";
  1008. std::cerr <<std::endl<< "\tcannot create:" <<d<<std::endl;
  1009. #endif
  1010. return 0;
  1011. }
  1012. #ifdef RSDIR_DEBUG
  1013. std::cerr << "check_create_directory()";
  1014. std::cerr <<std::endl<< "\tcreated:" <<d<<std::endl;
  1015. #endif
  1016. }
  1017. else if (!S_ISDIR(buf.st_mode))
  1018. {
  1019. // Some other type - error.
  1020. #ifdef RSDIR_DEBUG
  1021. std::cerr<<"check_create_directory() Fatal Error --";
  1022. std::cerr<<std::endl<<"\t"<<d<<" is nor Directory"<<std::endl;
  1023. #endif
  1024. return 0;
  1025. }
  1026. #ifdef RSDIR_DEBUG
  1027. std::cerr << "check_create_directory()";
  1028. std::cerr <<std::endl<< "\tDir Exists:" <<d<<std::endl;
  1029. #endif
  1030. return 1;
  1031. }
  1032. #include <dirent.h>
  1033. bool RsDirUtil::cleanupWideDirectory(std::wstring cleandir, std::list<std::wstring> keepFiles)
  1034. {
  1035. /* check for the dir existance */
  1036. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1037. std::string cd(cleandir.begin(), cleandir.end());
  1038. DIR *dir = opendir(cd.c_str());
  1039. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1040. std::list<std::wstring>::const_iterator it;
  1041. if (!dir)
  1042. {
  1043. return false;
  1044. }
  1045. struct dirent *dent;
  1046. struct stat buf;
  1047. while(NULL != (dent = readdir(dir)))
  1048. {
  1049. /* check entry type */
  1050. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1051. std::string fname(dent -> d_name);
  1052. std::wstring wfname(fname.begin(), fname.end());
  1053. std::string fullname = cd + "/" + fname;
  1054. if (-1 != stat(fullname.c_str(), &buf))
  1055. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1056. {
  1057. /* only worry about files */
  1058. if (S_ISREG(buf.st_mode))
  1059. {
  1060. /* check if we should keep it */
  1061. if (keepFiles.end() == (it = std::find(keepFiles.begin(), keepFiles.end(), wfname)))
  1062. {
  1063. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1064. /* can remove */
  1065. remove(fullname.c_str());
  1066. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1067. }
  1068. }
  1069. }
  1070. }
  1071. /* close directory */
  1072. closedir(dir);
  1073. return true;
  1074. }
  1075. /* slightly nicer helper function */
  1076. bool RsDirUtil::hashWideFile(std::wstring filepath,
  1077. std::wstring &name, std::string &hash, uint64_t &size)
  1078. {
  1079. if (getWideFileHash(filepath, hash, size))
  1080. {
  1081. /* extract file name */
  1082. name = RsDirUtil::getWideTopDir(filepath);
  1083. return true;
  1084. }
  1085. return false;
  1086. }
  1087. #include <openssl/sha.h>
  1088. #include <sstream>
  1089. #include <iomanip>
  1090. /* Function to hash, and get details of a file */
  1091. bool RsDirUtil::getWideFileHash(std::wstring filepath,
  1092. std::string &hash, uint64_t &size)
  1093. {
  1094. FILE *fd;
  1095. int len;
  1096. SHA_CTX *sha_ctx = new SHA_CTX;
  1097. unsigned char sha_buf[SHA_DIGEST_LENGTH];
  1098. unsigned char gblBuf[512];
  1099. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1100. std::string fp(filepath.begin(), filepath.end());
  1101. if (NULL == (fd = fopen64(fp.c_str(), "rb")))
  1102. return false;
  1103. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1104. /* determine size */
  1105. fseeko64(fd, 0, SEEK_END);
  1106. size = ftello64(fd);
  1107. fseeko64(fd, 0, SEEK_SET);
  1108. SHA1_Init(sha_ctx);
  1109. while((len = fread(gblBuf,1, 512, fd)) > 0)
  1110. {
  1111. SHA1_Update(sha_ctx, gblBuf, len);
  1112. }
  1113. /* reading failed for some reason */
  1114. if (ferror(fd))
  1115. {
  1116. delete sha_ctx;
  1117. fclose(fd);
  1118. return false;
  1119. }
  1120. SHA1_Final(&sha_buf[0], sha_ctx);
  1121. std::ostringstream tmpout; // please do not use std::ostringstream
  1122. for(int i = 0; i < SHA_DIGEST_LENGTH; i++)
  1123. {
  1124. tmpout << std::setw(2) << std::setfill('0') << std::hex << (unsigned int) (sha_buf[i]);
  1125. }
  1126. hash = tmpout.str();
  1127. delete sha_ctx;
  1128. fclose(fd);
  1129. return true;
  1130. }
  1131. bool RsDirUtil::renameWideFile(const std::wstring& from, const std::wstring& to)
  1132. {
  1133. int loops = 0;
  1134. #if defined(WIN32) || defined(MINGW) || defined(__CYGWIN__)
  1135. #ifdef WIN_CROSS_UBUNTU
  1136. std::wstring f,t ;
  1137. for(int i=0;i<from.size();++i) f.push_back(from[i]) ;
  1138. for(int i=0;i<to.size();++i) t.push_back(to[i]) ;
  1139. #else
  1140. std::wstring f(from),t(to) ;
  1141. #endif
  1142. while (!MoveFileEx(f.c_str(), t.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))
  1143. #else
  1144. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1145. std::string f(from.begin(), from.end());
  1146. std::string t(to.begin(), to.end());
  1147. while (rename(f.c_str(), t.c_str()) < 0)
  1148. /***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
  1149. #endif
  1150. {
  1151. #ifdef WIN32
  1152. if (GetLastError() != ERROR_ACCESS_DENIED)
  1153. #else
  1154. if (errno != EACCES)
  1155. #endif
  1156. /* set errno? */
  1157. return false ;
  1158. usleep(100 * 1000); //100 msec
  1159. if (loops >= 30)
  1160. return false ;
  1161. loops++;
  1162. }
  1163. return true ;
  1164. }
  1165. #endif // WIDE STUFF NOT ENABLED YET!