tc_file.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. /**
  2. * Tencent is pleased to support the open source community by making Tars available.
  3. *
  4. * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
  5. *
  6. * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  7. * in compliance with the License. You may obtain a copy of the License at
  8. *
  9. * https://opensource.org/licenses/BSD-3-Clause
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed
  12. * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  13. * CONDITIONS OF ANY KIND, either express or implied. See the License for the
  14. * specific language governing permissions and limitations under the License.
  15. */
  16. #include "util/tc_file.h"
  17. #include "util/tc_port.h"
  18. #include <set>
  19. #include <string.h>
  20. #if TARGET_PLATFORM_IOS
  21. #include <sys/proc_info.h>
  22. #include <libproc.h>
  23. #endif
  24. namespace tars
  25. {
  26. ifstream::pos_type TC_File::getFileSize(const string &sFullFileName)
  27. {
  28. ifstream ifs(sFullFileName.c_str());
  29. ifs.seekg(0, ios_base::end);
  30. return ifs.tellg();
  31. }
  32. bool TC_File::isAbsolute(const string &sFullFileName)
  33. {
  34. if(sFullFileName.empty())
  35. {
  36. return false;
  37. }
  38. unsigned i = 0;
  39. while(isspace(sFullFileName[i]))
  40. {
  41. ++i;
  42. }
  43. #if TARGET_PLATFORM_LINUX || TARGET_PLATFORM_IOS
  44. return sFullFileName[i] == FILE_SEP[0];
  45. #else
  46. if (sFullFileName.length() >= i + 2)
  47. {
  48. if (isPanfu(sFullFileName.substr(i, 2)))
  49. {
  50. return true;
  51. }
  52. }
  53. return false;
  54. #endif
  55. }
  56. bool TC_File::isFileExist(const string &sFullFileName, mode_t iFileType)
  57. {
  58. TC_Port::stat_t f_stat;
  59. if (TC_Port::lstat(sFullFileName.c_str(), &f_stat) == -1)
  60. {
  61. return false;
  62. }
  63. if (!(f_stat.st_mode & iFileType))
  64. {
  65. return false;
  66. }
  67. return true;
  68. }
  69. bool TC_File::isFileExistEx(const string &sFullFileName, mode_t iFileType)
  70. {
  71. struct stat f_stat;
  72. if (stat(sFullFileName.c_str(), &f_stat) == -1)
  73. {
  74. return false;
  75. }
  76. if (!(f_stat.st_mode & iFileType))
  77. {
  78. return false;
  79. }
  80. return true;
  81. }
  82. int TC_File::setExecutable(const string &sFullFileName, bool canExecutable)
  83. {
  84. #if TARGET_PLATFORM_LINUX || TARGET_PLATFORM_IOS
  85. struct stat f_stat;
  86. if (stat(sFullFileName.c_str(), &f_stat) == -1)
  87. {
  88. return -1;
  89. }
  90. return TC_Port::chmod(sFullFileName.c_str(), canExecutable ? f_stat.st_mode | S_IXUSR : f_stat.st_mode & ~S_IXUSR);
  91. #else
  92. return 0;
  93. #endif
  94. }
  95. struct classcomp
  96. {
  97. bool operator() (const string& lhs, const string& rhs) const
  98. {
  99. return TC_Port::strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
  100. }
  101. };
  102. bool TC_File::canExecutable(const string &sFullFileName)
  103. {
  104. #if TARGET_PLATFORM_WINDOWS
  105. string ex = extractFileExt(sFullFileName);
  106. static set<string, classcomp> ext = {"exe", "bat", "com"};
  107. return ext.find(ex) != ext.end();
  108. #else
  109. struct stat f_stat;
  110. if (stat(sFullFileName.c_str(), &f_stat) == -1)
  111. {
  112. return false;
  113. }
  114. return f_stat.st_mode & S_IXUSR;
  115. #endif
  116. }
  117. #if TARGET_PLATFORM_WINDOWS
  118. string TC_File::getExePath()
  119. {
  120. char exeFullPath[MAX_PATH]; // Full path
  121. GetModuleFileName(NULL, exeFullPath, MAX_PATH);
  122. return exeFullPath; // Get full path of the file
  123. }
  124. #elif TARGET_PLATFORM_IOS
  125. string TC_File::getExePath()
  126. {
  127. int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
  128. pid_t pids[numberOfProcesses];
  129. bzero(pids, sizeof(pids));
  130. proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
  131. char pathBuffer[PROC_PIDPATHINFO_MAXSIZE];
  132. bzero(pathBuffer, PROC_PIDPATHINFO_MAXSIZE);
  133. for (int i = 0; i < numberOfProcesses; ++i) {
  134. if (pids[i] == 0) { continue; }
  135. if(pids[i] == getpid())
  136. {
  137. proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer));
  138. break;
  139. }
  140. }
  141. return pathBuffer;
  142. }
  143. #else
  144. string TC_File::getExePath()
  145. {
  146. string proc = "/proc/self/exe";
  147. char buf[2048] = "\0";
  148. int bufsize = sizeof(buf) / sizeof(char);
  149. int count = readlink(proc.c_str(), buf, bufsize);
  150. if ( count < 0 )
  151. {
  152. THROW_EXCEPTION_SYSCODE(TC_File_Exception, "[TC_File::getExePath] could not get exe path error");
  153. // throw TC_File_Exception("[TC_File::getExePath] could not get exe path error", TC_Exception::getSystemCode());
  154. }
  155. count = (count >= bufsize) ? (bufsize - 1) : count;
  156. buf[count] = '\0';
  157. return buf;
  158. }
  159. #endif
  160. bool TC_File::makeDir(const string &sDirectoryPath)
  161. {
  162. int iRetCode = TC_Port::mkdir(sDirectoryPath.c_str());
  163. if(iRetCode < 0 && errno == EEXIST)
  164. {
  165. return isFileExistEx(sDirectoryPath, S_IFDIR);
  166. }
  167. return iRetCode == 0;
  168. }
  169. bool TC_File::makeDirRecursive(const string &sDirectoryPath)
  170. {
  171. string simple = simplifyDirectory(sDirectoryPath);
  172. string::size_type pos = 0;
  173. for(; pos != string::npos; )
  174. {
  175. pos = simple.find(FILE_SEP, pos + 1);
  176. string s;
  177. if(pos == string::npos)
  178. {
  179. s = simple.substr(0, simple.size());
  180. #if TARGET_PLATFORM_WINDOWS
  181. if (isPanfu(s))
  182. {
  183. return false;
  184. }
  185. #endif
  186. return makeDir(s.c_str());
  187. }
  188. else
  189. {
  190. s = simple.substr(0, pos);
  191. #if TARGET_PLATFORM_WINDOWS
  192. if (isPanfu(s))
  193. {
  194. continue;
  195. }
  196. #endif
  197. if(!makeDir(s.c_str())) return false;
  198. }
  199. }
  200. return true;
  201. }
  202. int TC_File::removeFile(const string &sFullFileName, bool bRecursive)
  203. {
  204. string path = simplifyDirectory(sFullFileName);
  205. if(isFileExist(path, S_IFDIR))
  206. {
  207. if(bRecursive)
  208. {
  209. vector<string> files;
  210. listDirectory(path, files, false);
  211. for(size_t i = 0; i < files.size(); i++)
  212. {
  213. removeFile(files[i], bRecursive);
  214. }
  215. if(path != FILE_SEP)
  216. {
  217. if(TC_Port::rmdir(path.c_str()) == -1)
  218. {
  219. return -1;
  220. }
  221. return 0;
  222. }
  223. }
  224. else
  225. {
  226. if(TC_Port::rmdir(path.c_str()) == -1)
  227. {
  228. return -1;
  229. }
  230. }
  231. }
  232. else
  233. {
  234. if(::remove(path.c_str()) == -1)
  235. {
  236. return -1;
  237. }
  238. }
  239. return 0;
  240. }
  241. int TC_File::renameFile(const string &sSrcFullFileName, const string &sDstFullFileName)
  242. {
  243. return rename(sSrcFullFileName.c_str(), sDstFullFileName.c_str());
  244. }
  245. string TC_File::simplifyDirectory(const string& path)
  246. {
  247. string result = path;
  248. #if TARGET_PLATFORM_WINDOWS
  249. result = TC_Common::replace(result, "/", "\\");
  250. #else
  251. result = TC_Common::replace(result, "\\", "/");
  252. #endif
  253. string sep(FILE_SEP);
  254. string::size_type pos;
  255. pos = 0;
  256. while((pos = result.find(sep + FILE_SEP, pos)) != string::npos)
  257. {
  258. result.erase(pos, 1);
  259. }
  260. pos = 0;
  261. while((pos = result.find(sep+ "." + FILE_SEP, pos)) != string::npos)
  262. {
  263. result.erase(pos, 2);
  264. }
  265. while(result.substr(0, 4) == sep + ".." + FILE_SEP)
  266. {
  267. result.erase(0, 3);
  268. }
  269. if(result.find(sep + ".." + FILE_SEP) != string::npos)
  270. {
  271. bool ab = TC_File::isAbsolute(result);
  272. vector<string> dirs = TC_Common::sepstr<string>(result, FILE_SEP);
  273. stack<string> q;
  274. for(size_t i = 0; i < dirs.size(); i++)
  275. {
  276. if(dirs[i] == ".." && !q.empty())
  277. {
  278. if(!TC_File::startWindowsPanfu(q.top()) && q.top() != ".." && q.top() != ".")
  279. q.pop();
  280. else
  281. {
  282. q.push(dirs[i]);
  283. }
  284. }
  285. else
  286. {
  287. q.push(dirs[i]);
  288. }
  289. }
  290. result = "";
  291. while(!q.empty())
  292. {
  293. result = q.top() + FILE_SEP + result;
  294. q.pop();
  295. }
  296. #if TARGET_PLATFORM_LINUX || TARGET_PLATFORM_IOS
  297. if(ab)
  298. {
  299. result = FILE_SEP + result;
  300. }
  301. #endif
  302. }
  303. if(result == sep + ".")
  304. {
  305. return result.substr(0, result.size() - 1);
  306. }
  307. if(result.size() >= 2 && result.substr(result.size() - 2, 2) == sep + ".")
  308. {
  309. result.erase(result.size() - 2, 2);
  310. }
  311. if(result == FILE_SEP)
  312. {
  313. return result;
  314. }
  315. if(result.size() >= 1 && result[result.size() - 1] == FILE_SEP[0])
  316. {
  317. result.erase(result.size() - 1);
  318. }
  319. if(result == sep + "..")
  320. {
  321. result = FILE_SEP;
  322. }
  323. return result;
  324. }
  325. string TC_File::load2str(const string &sFullFileName)
  326. {
  327. FILE *fd = TC_Port::fopen(sFullFileName.data(), "rb");
  328. if (fd == NULL)
  329. return "";
  330. string s;
  331. int nread = -1;
  332. do {
  333. char buf[8096] = {'\0'};
  334. nread = fread(buf, 1, sizeof(buf), fd);
  335. if (nread > 0)
  336. {
  337. s.append(buf, nread);
  338. }
  339. } while (nread > 0);
  340. fclose(fd);
  341. return s;
  342. }
  343. bool TC_File::load2str(const string &sFullFileName, vector<char> &data)
  344. {
  345. FILE *fd = TC_Port::fopen(sFullFileName.data(), "rb");
  346. if (fd == NULL)
  347. return false;
  348. int nread = -1;
  349. do {
  350. char buf[8096] = {'\0'};
  351. nread = fread(buf, 1, sizeof(buf), fd);
  352. if (nread > 0)
  353. {
  354. data.insert(data.end(), buf, buf+nread);
  355. }
  356. } while (nread > 0);
  357. fclose(fd);
  358. return true;
  359. }
  360. void TC_File::save2file(const string &sFullFileName, const string &sFileData)
  361. {
  362. save2file(sFullFileName, sFileData.c_str(), sFileData.length());
  363. }
  364. int TC_File::save2file(const string &sFullFileName, const char *sFileData, size_t length)
  365. {
  366. FILE *fp = TC_Port::fopen(sFullFileName.c_str(), "wb");
  367. if (fp == NULL)
  368. {
  369. return -1;
  370. }
  371. size_t ret = fwrite((void*)sFileData, 1, length, fp);
  372. fclose(fp);
  373. if(ret == length)
  374. {
  375. return 0;
  376. }
  377. return -1;
  378. }
  379. string TC_File::extractFileName(const string &sFullFileName)
  380. {
  381. if(sFullFileName.length() <= 0)
  382. {
  383. return "";
  384. }
  385. string::size_type found = sFullFileName.find_last_of("/\\");
  386. // string::size_type pos = sFullFileName.rfind(FILE_SEP);
  387. if(found == string::npos)
  388. {
  389. return sFullFileName;
  390. }
  391. return sFullFileName.substr(found + 1);
  392. }
  393. string TC_File::extractFilePath(const string &sFullFileName)
  394. {
  395. // #if TARGET_PLATFORM_WINDOWS
  396. // string sFullFileNameTmp = TC_Common::replace(sFullFileName, "/", "\\");
  397. // #else
  398. // string sFullFileNameTmp = TC_Common::replace(sFullFileName, "\\", "/");
  399. // #endif
  400. if (sFullFileName.length() <= 0)
  401. {
  402. return string(".") + FILE_SEP;
  403. }
  404. string::size_type found = sFullFileName.find_last_of("/\\");
  405. if(found == string::npos)
  406. {
  407. return string(".") + FILE_SEP;
  408. }
  409. return sFullFileName.substr(0, found+1);
  410. // return string(".") + FILE_SEP;
  411. }
  412. string TC_File::extractFileExt(const string &sFullFileName)
  413. {
  414. string::size_type found = sFullFileName.find_last_of("/\\");
  415. if(found == string::npos)
  416. {
  417. if ((found = sFullFileName.rfind('.')) == string::npos)
  418. {
  419. return string("");
  420. }
  421. return sFullFileName.substr(found+1);
  422. }
  423. else
  424. {
  425. for(string::size_type i = sFullFileName.size()-1; i > found; i--)
  426. {
  427. if(sFullFileName[i] == '.')
  428. {
  429. return sFullFileName.substr(i+1);
  430. }
  431. }
  432. return "";
  433. }
  434. }
  435. string TC_File::excludeFileExt(const string &sFullFileName)
  436. {
  437. string::size_type found = sFullFileName.find_last_of("./\\");
  438. if(found != string::npos)
  439. {
  440. if(sFullFileName[found] == '.')
  441. {
  442. return sFullFileName.substr(0, found);
  443. }
  444. }
  445. return sFullFileName;
  446. // return sFullFileName.substr(0, pos);
  447. }
  448. string TC_File::replaceFileExt(const string &sFullFileName, const string &sExt)
  449. {
  450. return excludeFileExt(sFullFileName) + "." + sExt;
  451. }
  452. string TC_File::extractUrlFilePath(const string &sUrl)
  453. {
  454. string sLowerUrl = TC_Common::lower(sUrl);
  455. string::size_type pos = sLowerUrl.find("http://");
  456. if(pos == 0)
  457. {
  458. pos += strlen("http://");
  459. }
  460. else if(pos == string::npos)
  461. {
  462. pos = 0;
  463. }
  464. for( ; pos < sUrl.length(); ++pos)
  465. {
  466. if(sUrl[pos] == '/')
  467. {
  468. if(pos < sUrl.length() - 1)
  469. {
  470. pos++;
  471. break;
  472. }
  473. else
  474. {
  475. return "";
  476. }
  477. }
  478. }
  479. if(pos == string::npos || pos == sUrl.length())
  480. {
  481. pos = 0;
  482. }
  483. return sUrl.substr(pos);
  484. }
  485. #if TARGET_PLATFORM_LINUX || TARGET_PLATFORM_IOS
  486. size_t TC_File::scanDir(const string &sFilePath, vector<string> &vtMatchFiles, FILE_SELECT f, int iMaxSize )
  487. {
  488. vtMatchFiles.clear();
  489. struct dirent **namelist;
  490. int n = scandir(sFilePath.c_str(), &namelist, f, alphasort);
  491. if (n < 0)
  492. {
  493. return 0;
  494. }
  495. else
  496. {
  497. while(n-- )
  498. {
  499. if(iMaxSize > 0 && vtMatchFiles.size() >= (size_t)iMaxSize )
  500. {
  501. free(namelist[n]);
  502. break;
  503. }
  504. else
  505. {
  506. vtMatchFiles.push_back(namelist[n]->d_name);
  507. free(namelist[n]);
  508. }
  509. }
  510. free(namelist);
  511. }
  512. return vtMatchFiles.size();
  513. }
  514. #endif
  515. void TC_File::listDirectory(const string &path, vector<string> &files, bool bRecursive, bool ignoreHide)
  516. {
  517. #if TARGET_PLATFORM_LINUX || TARGET_PLATFORM_IOS
  518. vector<string> tf;
  519. scanDir(path, tf, 0, 0);
  520. for(size_t i = 0; i < tf.size(); i++)
  521. {
  522. if(tf[i] == "." || tf[i] == "..")
  523. continue;
  524. if (ignoreHide && tf[i].at(0) == '.')
  525. continue;
  526. string s = path + FILE_SEP + tf[i];
  527. if(isFileExist(s, S_IFDIR))
  528. {
  529. files.push_back(simplifyDirectory(s));
  530. if(bRecursive)
  531. {
  532. listDirectory(s, files, bRecursive, ignoreHide);
  533. }
  534. }
  535. else
  536. {
  537. files.push_back(simplifyDirectory(s));
  538. }
  539. }
  540. #elif TARGET_PLATFORM_WINDOWS
  541. intptr_t hFile;
  542. _finddata_t fileinfo;
  543. if ((hFile = _findfirst(string(path + "\\*.*").c_str(), &fileinfo)) != -1)
  544. {
  545. do
  546. {
  547. string sName = fileinfo.name;
  548. if (sName == "." || sName == "..")
  549. continue;
  550. string s = path + FILE_SEP + sName;
  551. if (fileinfo.attrib & _A_SUBDIR)
  552. {
  553. files.push_back(simplifyDirectory(s));
  554. if (bRecursive)
  555. {
  556. listDirectory(s, files, bRecursive, ignoreHide);
  557. }
  558. }
  559. else
  560. {
  561. files.push_back(simplifyDirectory(s));
  562. }
  563. } while (_findnext(hFile, &fileinfo) == 0);
  564. _findclose(hFile);
  565. }
  566. #endif
  567. }
  568. void TC_File::copyFile(const string &sExistFile, const string &sNewFile,bool bRemove)
  569. {
  570. if(TC_File::isFileExist(sExistFile, S_IFDIR))
  571. {
  572. TC_File::makeDir(sNewFile);
  573. vector<string> tf;
  574. TC_File::listDirectory(sExistFile,tf, false);
  575. for(size_t i = 0; i <tf.size(); i++)
  576. {
  577. string fileName = TC_File::extractFileName(tf[i]);
  578. if(fileName == "." || fileName == "..")
  579. continue;
  580. string s = sExistFile + FILE_SEP + fileName;
  581. string d = sNewFile + FILE_SEP + fileName;
  582. copyFile(s, d,bRemove);
  583. }
  584. }
  585. else
  586. {
  587. if(bRemove) std::remove(sNewFile.c_str());
  588. std::ifstream fin(sExistFile.c_str(), ios::binary);
  589. if(!fin)
  590. {
  591. THROW_EXCEPTION_SYSCODE(TC_File_Exception, "[TC_File::copyFile] error: "+sExistFile);
  592. }
  593. std::ofstream fout(sNewFile.c_str(), ios::binary);
  594. if(!fout )
  595. {
  596. THROW_EXCEPTION_SYSCODE(TC_File_Exception, "[TC_File::copyFile] error: "+sNewFile);
  597. }
  598. fout << fin.rdbuf();
  599. fin.close();
  600. fout.close();
  601. TC_Port::stat_t f_stat;
  602. if (TC_Port::lstat(sExistFile.c_str(), &f_stat) == -1)
  603. {
  604. THROW_EXCEPTION_SYSCODE(TC_File_Exception, "[TC_File::copyFile] error: "+sExistFile);
  605. }
  606. TC_Port::chmod(sNewFile.c_str(),f_stat.st_mode);
  607. }
  608. }
  609. bool TC_File::startWindowsPanfu(const string & sPath)
  610. {
  611. if (sPath.length() < 2)
  612. {
  613. return false;
  614. }
  615. char c = sPath[0];
  616. return isalpha(c) && (sPath[1] == ':');
  617. }
  618. bool TC_File::isPanfu(const string & sPath)
  619. {
  620. if (sPath.length() != 2)
  621. {
  622. return false;
  623. }
  624. char c = sPath[0];
  625. return isalpha(c) && (sPath[1] == ':');
  626. }
  627. }